Tarantool development patches archive
 help / color / mirror / Atom feed
* [Tarantool-patches] [PATCH v1 1/1] sql: remove implicit cast for COMPARISON
@ 2020-03-20 12:34 imeevma
  2020-03-29 22:29 ` Vladislav Shpilevoy
  0 siblings, 1 reply; 8+ messages in thread
From: imeevma @ 2020-03-20 12:34 UTC (permalink / raw)
  To: v.shpilevoy, tsafin, tarantool-patches

This patch removes implicit cast for comparison. Also, it make
search using an index work the same way as in case of fullscan in
most cases.

Closes #4230
Closes #4783
---
https://github.com/tarantool/tarantool/issues/4230
https://github.com/tarantool/tarantool/issues/4783
https://github.com/tarantool/tarantool/tree/imeevma/gh-4230-remove-implicit-cast-for-index-search-second

@ChangeLog Remove implicit cast for comparison gh-4230

 src/box/sql/sqlInt.h                  |   3 +
 src/box/sql/vdbe.c                    | 638 +++++++++++++++++++---------------
 src/box/sql/vdbemem.c                 |   1 +
 src/box/sql/where.c                   |   4 +-
 src/box/sql/wherecode.c               | 204 +----------
 src/box/tuple_compare.cc              |   6 +
 src/box/tuple_compare.h               |   9 +
 test/sql-tap/identifier_case.test.lua |   6 +-
 test/sql-tap/in1.test.lua             |  14 +-
 test/sql-tap/in4.test.lua             |  40 +--
 test/sql-tap/index1.test.lua          |   4 +-
 test/sql-tap/insert3.test.lua         |   2 +-
 test/sql-tap/intpkey.test.lua         |  12 +-
 test/sql-tap/join.test.lua            |   8 +-
 test/sql-tap/misc1.test.lua           |  32 +-
 test/sql-tap/select1.test.lua         |  10 +-
 test/sql-tap/select7.test.lua         |   2 +-
 test/sql-tap/sql-errors.test.lua      |   4 +-
 test/sql-tap/subquery.test.lua        |   4 +-
 test/sql-tap/tkt-9a8b09f8e6.test.lua  |  88 ++---
 test/sql-tap/tkt-f973c7ac31.test.lua  |  34 +-
 test/sql-tap/tkt-fc7bd6358f.test.lua  |   8 +-
 test/sql-tap/tkt3493.test.lua         |  30 +-
 test/sql-tap/transitive1.test.lua     |  16 +-
 test/sql-tap/where2.test.lua          |  24 +-
 test/sql-tap/where5.test.lua          |  12 +-
 test/sql-tap/whereB.test.lua          |  80 ++---
 test/sql-tap/whereC.test.lua          |  10 +-
 test/sql/boolean.result               | 230 ++++++------
 test/sql/types.result                 |   7 +-
 test/sql/types.test.lua               |   2 +-
 31 files changed, 702 insertions(+), 842 deletions(-)

diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index 1579cc9..cd626bd 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -1304,6 +1304,9 @@ enum trim_side_mask {
 				 (X) == FIELD_TYPE_UNSIGNED || \
 				 (X) == FIELD_TYPE_DOUBLE)
 
+#define sql_mp_type_is_numeric(X)  ((X) == MP_INT || (X) == MP_UINT || \
+				    (X) == MP_FLOAT || (X) == MP_DOUBLE)
+
 /*
  * Additional bit values that can be ORed with an type without
  * changing the type.
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index e8a029a..8c95fd4 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -660,6 +660,216 @@ vdbe_field_ref_fetch_field(struct vdbe_field_ref *field_ref, uint32_t fieldno)
 }
 
 /**
+ * Prepare mem to use for comparison with value with type UNSIGNED
+ * from index.
+ *
+ * @param[out] mem Mem to prepare for comparison.
+ * @param[in][out] op Operation that was before preperation and
+ *                 operation after.
+ * @param is_eq True if operation was EQ.
+ * @param[out] is_none True if nothing will be found.
+ * @retval 0 on success.
+ * @retval -1 on error.
+ */
+static int
+sql_mem_to_unsigned_for_comp(struct Mem *mem, uint32_t *op, int is_eq,
+			     bool *is_none)
+{
+	assert(*is_none == false);
+	uint32_t orig_op = *op;
+	enum mp_type mp_type = sql_value_type(mem);
+	assert(mp_type == MP_DOUBLE || mp_type == MP_INT);
+	if (mp_type == MP_INT || mem->u.r < 0) {
+		if (orig_op == OP_SeekGE || orig_op == OP_SeekGT) {
+			mem_set_u64(mem, 0);
+			*op = OP_SeekGE;
+			return 0;
+		}
+		*is_none = true;
+		return 0;
+	}
+	double d = mem->u.r;
+	if (d >= UINT64_MAX) {
+		if (orig_op == OP_SeekLE || orig_op == OP_SeekLT) {
+			mem_set_u64(mem, UINT64_MAX);
+			*op = OP_SeekLE;
+			return 0;
+		}
+		*is_none = true;
+		return 0;
+	}
+	uint64_t u = (uint64_t)d;
+	if (d != u && is_eq) {
+		*is_none = true;
+		return 0;
+	}
+	mem_set_u64(mem, u);
+	if (d == u)
+		return 0;
+	if (orig_op == OP_SeekGE)
+		*op = OP_SeekGT;
+	else if (orig_op == OP_SeekLT)
+		*op = OP_SeekLE;
+	return 0;
+}
+
+/**
+ * Prepare mem to use for comparison with value with type INTEGER
+ * from index.
+ *
+ * @param[out] mem Mem to prepare for comparison.
+ * @param[in][out] op Operation that was before preperation and
+ *                 operation after.
+ * @param is_eq True if operation was EQ.
+ * @param[out] is_none True if nothing will be found.
+ * @retval 0 on success.
+ * @retval -1 on error.
+ */
+static int
+sql_mem_to_integer_for_comp(struct Mem *mem, uint32_t *op, int is_eq,
+			    bool *is_none)
+{
+	assert(*is_none == false);
+	uint32_t orig_op = *op;
+	assert(sql_value_type(mem) == MP_DOUBLE);
+	double d = mem->u.r;
+	if (d < INT64_MIN) {
+		if (orig_op == OP_SeekGE || orig_op == OP_SeekGT) {
+			mem_set_i64(mem, INT64_MIN);
+			*op = OP_SeekGE;
+			return 0;
+		}
+		*is_none = true;
+		return 0;
+	}
+	if (d >= UINT64_MAX) {
+		if (orig_op == OP_SeekLE || orig_op == OP_SeekLT) {
+			mem_set_u64(mem, UINT64_MAX);
+			*op = OP_SeekLE;
+			return 0;
+		}
+		*is_none = true;
+		return 0;
+	}
+	int64_t i = (int64_t)d;
+	uint64_t u = (uint64_t)d;
+	if (d != i && d != u && is_eq) {
+		*is_none = true;
+		return 0;
+	}
+	if (d > 0)
+		mem_set_u64(mem, u);
+	else
+		mem_set_i64(mem, i);
+	if (d == u || d == i)
+		return 0;
+	if (d >= 0) {
+		if (orig_op == OP_SeekGE)
+			*op = OP_SeekGT;
+		else if (orig_op == OP_SeekLT)
+			*op = OP_SeekLE;
+		return 0;
+	}
+	if (orig_op == OP_SeekLE)
+		*op = OP_SeekLT;
+	else if (orig_op == OP_SeekGT)
+		*op = OP_SeekGE;
+	return 0;
+}
+
+/**
+ * Prepare mem to use for comparison with value with type DOUBLE
+ * from index.
+ *
+ * @param[out] mem Mem to prepare for comparison.
+ * @param[in][out] op Operation that was before preperation and
+ *                 operation after.
+ * @param is_eq True if operation was EQ.
+ * @param[out] is_none True if nothing will be found.
+ * @retval 0 on success.
+ * @retval -1 on error.
+ */
+static int
+sql_mem_to_double_for_comp(struct Mem *mem, uint32_t *op, int is_eq,
+			   bool *is_none)
+{
+	assert(*is_none == false);
+	uint32_t orig_op = *op;
+	enum mp_type mp_type = sql_value_type(mem);
+	assert(mp_type == MP_INT || mp_type == MP_UINT);
+	int64_t i = mem->u.i;
+	uint64_t u = mem->u.u;
+	/* 2^53 == 9007199254740992 */
+	if (mp_type == MP_INT && i > -9007199254740992) {
+		sqlVdbeMemSetDouble(mem, i);
+		return 0;
+	} else if (mp_type == MP_UINT && u < 9007199254740992) {
+		sqlVdbeMemSetDouble(mem, u);
+		return 0;
+	}
+
+	double d = mp_type == MP_INT ? (double)i : (double)u;
+	if (is_eq) {
+		if (i != d && u != d)
+			*is_none = true;
+		else
+			sqlVdbeMemSetDouble(mem, d);
+		return 0;
+	}
+
+	sqlVdbeMemSetDouble(mem, d);
+	if (mp_type == MP_INT) {
+		if (orig_op == OP_SeekGT && d > i)
+			*op = OP_SeekGE;
+		else if (orig_op == OP_SeekGE && d < i)
+			*op = OP_SeekGT;
+		else if (orig_op == OP_SeekLT && d < i)
+			*op = OP_SeekLE;
+		else if (orig_op == OP_SeekLE && d > i)
+			*op = OP_SeekLT;
+		return 0;
+	}
+	if (orig_op == OP_SeekGT && d > u)
+		*op = OP_SeekGE;
+	else if (orig_op == OP_SeekGE && d < u)
+		*op = OP_SeekGT;
+	else if (orig_op == OP_SeekLT && d < u)
+		*op = OP_SeekLE;
+	else if (orig_op == OP_SeekLE && d > u)
+		*op = OP_SeekLT;
+	return 0;
+}
+
+/**
+ * Prepare mem to use for comparison with value with numeric type
+ * from index.
+ *
+ * @param[in][out] r Unpacked tuple that should be prepared for
+ *                 comparison.
+ * @param i field of unpacked tuple that should be prepared.
+ * @param is_eq True if operation was EQ.
+ * @param[out] is_none True if nothing will be found.
+ * @retval 0 on success.
+ * @retval -1 on error.
+ */
+static int
+sql_prepare_rec_for_comp(struct UnpackedRecord *r, int i, int is_eq,
+			 bool *is_none)
+{
+	struct Mem *mem = &r->aMem[i];
+	enum field_type field_type = r->key_def->parts[i].type;
+	uint32_t opcode = r->opcode;
+	if (field_type == FIELD_TYPE_UNSIGNED)
+		sql_mem_to_unsigned_for_comp(mem, &opcode, is_eq, is_none);
+	else if (field_type == FIELD_TYPE_INTEGER)
+		sql_mem_to_integer_for_comp(mem, &opcode, is_eq, is_none);
+	else
+		sql_mem_to_double_for_comp(mem, &opcode, is_eq, is_none);
+	r->opcode = opcode;
+	return 0;
+}
+
+/**
  * Find the left closest field for a given fieldno in field_ref's
  * slot_bitmask. The fieldno is expected to be greater than 0.
  * @param field_ref The vdbe_field_ref instance to use.
@@ -2050,15 +2260,15 @@ case OP_Cast: {                  /* in1 */
  * jump to address P2.  Or if the SQL_STOREP2 flag is set in P5, then
  * store the result of comparison in register P2.
  *
- * Once any conversions have taken place, and neither value is NULL,
- * the values are compared. If both values are blobs then memcmp() is
- * used to determine the results of the comparison.  If both values
- * are text, then the appropriate collating function specified in
- * P4 is used to do the comparison.  If P4 is not specified then
- * memcmp() is used to compare text string.  If both values are
- * numeric, then a numeric comparison is used. If the two values
- * are of different types, then numbers are considered less than
- * strings and strings are considered less than blobs.
+ * If neither value is NULL, the values are compared. If both
+ * values are blobs then memcmp() is used to determine the results
+ * of the comparison. If both values are booleans, TRUE if more
+ * than FALSE. If both values are text, then the appropriate
+ * collating function specified in P4 is used to do the
+ * comparison. If P4 is not specified then memcmp() is used to
+ * compare text string. If both values are numeric, then a numeric
+ * comparison is used. If both values are not NULL and the above
+ * rules cannot be applied to them, an error is generated.
  *
  * If SQL_NULLEQ is set in P5 then the result of comparison is always either
  * true or false and is never NULL.  If both operands are NULL then the result
@@ -2096,15 +2306,8 @@ case OP_Cast: {                  /* in1 */
  * reg(P3) is NULL then the take the jump.  If the SQL_JUMPIFNULL
  * bit is clear then fall through if either operand is NULL.
  *
- * Once any conversions have taken place, and neither value is NULL,
- * the values are compared. If both values are blobs then memcmp() is
- * used to determine the results of the comparison.  If both values
- * are text, then the appropriate collating function specified in
- * P4 is  used to do the comparison.  If P4 is not specified then
- * memcmp() is used to compare text string.  If both values are
- * numeric, then a numeric comparison is used. If the two values
- * are of different types, then numbers are considered less than
- * strings and strings are considered less than blobs.
+ * See the Eq opcode for additional information about comparison
+ * rules.
  */
 /* Opcode: Le P1 P2 P3 P4 P5
  * Synopsis: IF r[P3]<=r[P1]
@@ -2133,189 +2336,109 @@ case OP_Lt:               /* same as TK_LT, jump, in1, in3 */
 case OP_Le:               /* same as TK_LE, jump, in1, in3 */
 case OP_Gt:               /* same as TK_GT, jump, in1, in3 */
 case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
-	int res, res2;      /* Result of the comparison of pIn1 against pIn3 */
-	u32 flags1;         /* Copy of initial value of pIn1->flags */
-	u32 flags3;         /* Copy of initial value of pIn3->flags */
-
+	/*
+	 * Result of comparison: more than 0 if l > r,
+	 * 0 if l == r, less than 0 if l < r.
+	 */
+	int cmp_res;
+	/* Result of the operation. */
+	bool result;
 	pIn1 = &aMem[pOp->p1];
 	pIn3 = &aMem[pOp->p3];
-	flags1 = pIn1->flags;
-	flags3 = pIn3->flags;
-	enum field_type ft_p1 = pIn1->field_type;
-	enum field_type ft_p3 = pIn3->field_type;
-	if ((flags1 | flags3)&MEM_Null) {
-		/* One or both operands are NULL */
-		if (pOp->p5 & SQL_NULLEQ) {
-			/* If SQL_NULLEQ is set (which will only happen if the operator is
-			 * OP_Eq or OP_Ne) then take the jump or not depending on whether
-			 * or not both operands are null.
-			 */
-			assert(pOp->opcode==OP_Eq || pOp->opcode==OP_Ne);
-			assert((flags1 & MEM_Cleared)==0);
-			assert((pOp->p5 & SQL_JUMPIFNULL)==0);
-			if ((flags1&flags3&MEM_Null)!=0
-			    && (flags3&MEM_Cleared)==0
-				) {
-				res = 0;  /* Operands are equal */
-			} else {
-				res = 1;  /* Operands are not equal */
-			}
-		} else {
-			/* SQL_NULLEQ is clear and at least one operand is NULL,
-			 * then the result is always NULL.
-			 * The jump is taken if the SQL_JUMPIFNULL bit is set.
+
+	bool has_scalar = (pIn1->field_type == FIELD_TYPE_SCALAR) ||
+			  (pIn3->field_type == FIELD_TYPE_SCALAR);
+	enum mp_type ltype = sql_value_type(pIn1);
+	enum mp_type rtype = sql_value_type(pIn3);
+	assert(ltype != MP_MAP && rtype != MP_MAP);
+	assert(ltype != MP_ARRAY && rtype != MP_ARRAY);
+	int mp_classes_comp = mp_type_classes_comp(rtype, ltype);
+
+	if (ltype == MP_NIL || rtype == MP_NIL) {
+		if ((pOp->p5 & SQL_NULLEQ) == 0) {
+			/*
+			 * SQL_NULLEQ is clear and at least one
+			 * operand is NULL, then the result is
+			 * always NULL. The jump is taken if the
+			 * SQL_JUMPIFNULL bit is set.
 			 */
 			if (pOp->p5 & SQL_STOREP2) {
 				pOut = vdbe_prepare_null_out(p, pOp->p2);
-				iCompare = 1;    /* Operands are not equal */
+				iCompare = 1;
 				REGISTER_TRACE(p, pOp->p2, pOut);
 			} else {
 				VdbeBranchTaken(2,3);
-				if (pOp->p5 & SQL_JUMPIFNULL) {
+				if (pOp->p5 & SQL_JUMPIFNULL)
 					goto jump_to_p2;
-				}
 			}
 			break;
 		}
-	} else if (((flags1 | flags3) & MEM_Bool) != 0 ||
-		   ((flags1 | flags3) & MEM_Blob) != 0) {
 		/*
-		 * If one of values is of type BOOLEAN or VARBINARY,
-		 * then the second one must be of the same type as
-		 * well. Otherwise an error is raised.
+		 * If SQL_NULLEQ is set (which will only happen if
+		 * the operator is OP_Eq or OP_Ne) then take the
+		 * jump or not depending on whether or not both
+		 * operands are null.
 		 */
-		int type_arg1 = flags1 & (MEM_Bool | MEM_Blob);
-		int type_arg3 = flags3 & (MEM_Bool | MEM_Blob);
-		if (type_arg1 != type_arg3) {
-			char *inconsistent_type = type_arg1 != 0 ?
-						  mem_type_to_str(pIn3) :
-						  mem_type_to_str(pIn1);
-			char *expected_type     = type_arg1 != 0 ?
-						  mem_type_to_str(pIn1) :
-						  mem_type_to_str(pIn3);
-			diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
-				 inconsistent_type, expected_type);
-			goto abort_due_to_error;
-		}
-		res = sqlMemCompare(pIn3, pIn1, NULL);
+		assert(pOp->opcode == OP_Eq || pOp->opcode == OP_Ne);
+		assert((pOp->p5 & SQL_JUMPIFNULL) == 0);
+		cmp_res = !(ltype == MP_NIL && rtype == MP_NIL);
+	} else if (mp_classes_comp == 0) {
+		cmp_res = sqlMemCompare(pIn3, pIn1, pOp->p4.pColl);
+	} else if (has_scalar) {
+		cmp_res = mp_classes_comp;
 	} else {
-		enum field_type type = pOp->p5 & FIELD_TYPE_MASK;
-		if (sql_type_is_numeric(type)) {
-			if ((flags1 | flags3)&MEM_Str) {
-				if ((flags1 & MEM_Str) == MEM_Str) {
-					mem_apply_numeric_type(pIn1);
-					testcase( flags3!=pIn3->flags); /* Possible if pIn1==pIn3 */
-					flags3 = pIn3->flags;
-				}
-				if ((flags3 & MEM_Str) == MEM_Str) {
-					if (mem_apply_numeric_type(pIn3) != 0) {
-						diag_set(ClientError,
-							 ER_SQL_TYPE_MISMATCH,
-							 sql_value_to_diag_str(pIn3),
-							 "numeric");
-						goto abort_due_to_error;
-					}
+		diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+			 mem_type_to_str(pIn1), mem_type_to_str(pIn3));
+		goto abort_due_to_error;
+	}
 
-				}
-			}
-			/* Handle the common case of integer comparison here, as an
-			 * optimization, to avoid a call to sqlMemCompare()
-			 */
-			if ((pIn1->flags & pIn3->flags & (MEM_Int | MEM_UInt)) != 0) {
-				if ((pIn1->flags & pIn3->flags & MEM_Int) != 0) {
-					if (pIn3->u.i > pIn1->u.i)
-						res = +1;
-					else if (pIn3->u.i < pIn1->u.i)
-						res = -1;
-					else
-						res = 0;
-					goto compare_op;
-				}
-				if ((pIn1->flags & pIn3->flags & MEM_UInt) != 0) {
-					if (pIn3->u.u > pIn1->u.u)
-						res = +1;
-					else if (pIn3->u.u < pIn1->u.u)
-						res = -1;
-					else
-						res = 0;
-					goto compare_op;
-				}
-				if ((pIn1->flags & MEM_UInt) != 0 &&
-				    (pIn3->flags & MEM_Int) != 0) {
-					res = -1;
-					goto compare_op;
-				}
-				res = 1;
-				goto compare_op;
-			}
-		} else if (type == FIELD_TYPE_STRING) {
-			if ((flags1 & MEM_Str) == 0 &&
-			    (flags1 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
-				testcase( pIn1->flags & MEM_Int);
-				testcase( pIn1->flags & MEM_Real);
-				sqlVdbeMemStringify(pIn1);
-				testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn));
-				flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
-				assert(pIn1!=pIn3);
-			}
-			if ((flags3 & MEM_Str) == 0 &&
-			    (flags3 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
-				testcase( pIn3->flags & MEM_Int);
-				testcase( pIn3->flags & MEM_Real);
-				sqlVdbeMemStringify(pIn3);
-				testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn));
-				flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & MEM_TypeMask);
-			}
-		}
-		assert(pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0);
-		res = sqlMemCompare(pIn3, pIn1, pOp->p4.pColl);
-	}
-			compare_op:
-	switch( pOp->opcode) {
-	case OP_Eq:    res2 = res==0;     break;
-	case OP_Ne:    res2 = res;        break;
-	case OP_Lt:    res2 = res<0;      break;
-	case OP_Le:    res2 = res<=0;     break;
-	case OP_Gt:    res2 = res>0;      break;
-	default:       res2 = res>=0;     break;
-	}
-
-	/* Undo any changes made by mem_apply_type() to the input registers. */
-	assert((pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn));
-	pIn1->flags = flags1;
-	pIn1->field_type = ft_p1;
-	assert((pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn));
-	pIn3->flags = flags3;
-	pIn3->field_type = ft_p3;
+	switch (pOp->opcode) {
+	case OP_Eq:
+		result = cmp_res == 0;
+		break;
+	case OP_Ne:
+		result = cmp_res != 0;
+		break;
+	case OP_Lt:
+		result = cmp_res < 0;
+		break;
+	case OP_Le:
+		result = cmp_res <= 0;
+		break;
+	case OP_Gt:
+		result = cmp_res > 0;
+		break;
+	case OP_Ge:
+		result = cmp_res >= 0;
+		break;
+	default:
+		unreachable();
+	}
 
 	if (pOp->p5 & SQL_STOREP2) {
-		iCompare = res;
-		res2 = res2!=0;  /* For this path res2 must be exactly 0 or 1 */
-		if ((pOp->p5 & SQL_KEEPNULL)!=0) {
-			/* The KEEPNULL flag prevents OP_Eq from overwriting a NULL with true
-			 * and prevents OP_Ne from overwriting NULL with false.  This flag
-			 * is only used in contexts where either:
-			 *   (1) op==OP_Eq && (r[P2]==NULL || r[P2]==0)
-			 *   (2) op==OP_Ne && (r[P2]==NULL || r[P2]==1)
-			 * Therefore it is not necessary to check the content of r[P2] for
-			 * NULL.
-			 */
-			assert(pOp->opcode==OP_Ne || pOp->opcode==OP_Eq);
-			assert(res2==0 || res2==1);
-			testcase( res2==0 && pOp->opcode==OP_Eq);
-			testcase( res2==1 && pOp->opcode==OP_Eq);
-			testcase( res2==0 && pOp->opcode==OP_Ne);
-			testcase( res2==1 && pOp->opcode==OP_Ne);
-			if ((pOp->opcode==OP_Eq)==res2) break;
+		iCompare = cmp_res;
+		/*
+		 * The KEEPNULL flag prevents OP_Eq from
+		 * overwriting a NULL with true and prevents OP_Ne
+		 * from overwriting NULL with false. This flag
+		 * is only used in contexts where either:
+		 *   (1) op==OP_Eq && (r[P2]==NULL || r[P2]==0)
+		 *   (2) op==OP_Ne && (r[P2]==NULL || r[P2]==1)
+		 * Therefore it is not necessary to check the
+		 * content of r[P2] for NULL.
+		 */
+		if ((pOp->p5 & SQL_KEEPNULL) != 0) {
+			assert(pOp->opcode == OP_Ne || pOp->opcode == OP_Eq);
+			if ((pOp->opcode == OP_Eq) == result)
+				break;
 		}
 		pOut = vdbe_prepare_null_out(p, pOp->p2);
-		mem_set_bool(pOut, res2);
+		mem_set_bool(pOut, result);
 		REGISTER_TRACE(p, pOp->p2, pOut);
 	} else {
-		VdbeBranchTaken(res!=0, (pOp->p5 & SQL_NULLEQ)?2:3);
-		if (res2) {
+		VdbeBranchTaken(cmp_res != 0, (pOp->p5 & SQL_NULLEQ) ? 2 : 3);
+		if (result)
 			goto jump_to_p2;
-		}
 	}
 	break;
 }
@@ -3346,7 +3469,6 @@ case OP_SeekGT: {       /* jump, in3 */
 	VdbeCursor *pC;    /* The cursor to seek */
 	UnpackedRecord r;  /* The key to seek for */
 	int nField;        /* Number of columns or fields in the key */
-	i64 iKey;          /* The id we are to seek to */
 	int eqOnly;        /* Only interested in == results */
 
 	assert(pOp->p1>=0 && pOp->p1<p->nCursor);
@@ -3364,86 +3486,6 @@ case OP_SeekGT: {       /* jump, in3 */
 #ifdef SQL_DEBUG
 	pC->seekOp = pOp->opcode;
 #endif
-	iKey = 0;
-	/*
-	 * In case floating value is intended to be passed to
-	 * iterator over integer field, we must truncate it to
-	 * integer value and change type of iterator:
-	 * a > 1.5 -> a >= 2
-	 */
-	int int_field = pOp->p5;
-	bool is_neg = false;
-
-	if (int_field > 0) {
-		/* The input value in P3 might be of any type: integer, real, string,
-		 * blob, or NULL.  But it needs to be an integer before we can do
-		 * the seek, so convert it.
-		 */
-		pIn3 = &aMem[int_field];
-		if ((pIn3->flags & MEM_Null) != 0)
-			goto skip_truncate;
-		if ((pIn3->flags & MEM_Str) != 0)
-			mem_apply_numeric_type(pIn3);
-		int64_t i;
-		if ((pIn3->flags & MEM_Int) == MEM_Int) {
-			i = pIn3->u.i;
-			is_neg = true;
-		} else if ((pIn3->flags & MEM_UInt) == MEM_UInt) {
-			i = pIn3->u.u;
-			is_neg = false;
-		} else if ((pIn3->flags & MEM_Real) == MEM_Real) {
-			if (pIn3->u.r > INT64_MAX)
-				i = INT64_MAX;
-			else if (pIn3->u.r < INT64_MIN)
-				i = INT64_MIN;
-			else
-				i = pIn3->u.r;
-			is_neg = i < 0;
-		} else {
-			diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
-				 sql_value_to_diag_str(pIn3), "integer");
-			goto abort_due_to_error;
-		}
-		iKey = i;
-
-		/* If the P3 value could not be converted into an integer without
-		 * loss of information, then special processing is required...
-		 */
-		if ((pIn3->flags & (MEM_Int | MEM_UInt)) == 0) {
-			if ((pIn3->flags & MEM_Real)==0) {
-				/* If the P3 value cannot be converted into any kind of a number,
-				 * then the seek is not possible, so jump to P2
-				 */
-				VdbeBranchTaken(1,2); goto jump_to_p2;
-				break;
-			}
-
-			/* If the approximation iKey is larger than the actual real search
-			 * term, substitute >= for > and < for <=. e.g. if the search term
-			 * is 4.9 and the integer approximation 5:
-			 *
-			 *        (x >  4.9)    ->     (x >= 5)
-			 *        (x <= 4.9)    ->     (x <  5)
-			 */
-			if (pIn3->u.r<(double)iKey) {
-				assert(OP_SeekGE==(OP_SeekGT-1));
-				assert(OP_SeekLT==(OP_SeekLE-1));
-				assert((OP_SeekLE & 0x0001)==(OP_SeekGT & 0x0001));
-				if ((oc & 0x0001)==(OP_SeekGT & 0x0001)) oc--;
-			}
-
-			/* If the approximation iKey is smaller than the actual real search
-			 * term, substitute <= for < and > for >=.
-			 */
-			else if (pIn3->u.r>(double)iKey) {
-				assert(OP_SeekLE==(OP_SeekLT+1));
-				assert(OP_SeekGT==(OP_SeekGE+1));
-				assert((OP_SeekLT & 0x0001)==(OP_SeekGE & 0x0001));
-				if ((oc & 0x0001)==(OP_SeekLT & 0x0001)) oc++;
-			}
-		}
-	}
-skip_truncate:
 	/*
 	 * For a cursor with the OPFLAG_SEEKEQ hint, only the
 	 * OP_SeekGE and OP_SeekLE opcodes are allowed, and these
@@ -3465,22 +3507,38 @@ skip_truncate:
 	assert(nField>0);
 	r.key_def = pC->key_def;
 	r.nField = (u16)nField;
-
-	if (int_field > 0)
-		mem_set_int(&aMem[int_field], iKey, is_neg);
-
-	r.default_rc = ((1 & (oc - OP_SeekLT)) ? -1 : +1);
-	assert(oc!=OP_SeekGT || r.default_rc==-1);
-	assert(oc!=OP_SeekLE || r.default_rc==-1);
-	assert(oc!=OP_SeekGE || r.default_rc==+1);
-	assert(oc!=OP_SeekLT || r.default_rc==+1);
-
 	r.aMem = &aMem[pOp->p3];
 #ifdef SQL_DEBUG
 	{ int i; for(i=0; i<r.nField; i++) assert(memIsValid(&r.aMem[i])); }
 #endif
 	r.eqSeen = 0;
 	r.opcode = oc;
+	for (int i = 0; i < nField; ++i) {
+		struct Mem *mem = &r.aMem[i];
+		enum mp_type mp_type = sql_value_type(mem);
+		enum field_type field_type = r.key_def->parts[i].type;
+		bool is_nullable = r.key_def->parts[i].nullable_action ==
+				   ON_CONFLICT_ACTION_NONE;
+		if (field_mp_plain_type_is_compatible(field_type, mp_type,
+						      is_nullable))
+			continue;
+		if (!sql_type_is_numeric(field_type) ||
+		    !sql_mp_type_is_numeric(mp_type)) {
+			diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+				 mem_type_to_str(mem),
+				 field_type_strs[field_type]);
+			goto abort_due_to_error;
+		}
+		bool is_none = false;
+		if (sql_prepare_rec_for_comp(&r, i, eqOnly, &is_none) != 0)
+			goto abort_due_to_error;
+		oc = r.opcode;
+		if (is_none) {
+			res = 1;
+			goto seek_not_found;
+		}
+	}
+
 	if (sqlCursorMovetoUnpacked(pC->uc.pCursor, &r, &res) != 0)
 		goto abort_due_to_error;
 	if (eqOnly && r.eqSeen==0) {
@@ -4595,26 +4653,36 @@ case OP_IdxGE:  {       /* jump */
 	assert(pOp->p4type==P4_INT32);
 	r.key_def = pC->key_def;
 	r.nField = (u16)pOp->p4.i;
-	if (pOp->opcode<OP_IdxLT) {
-		assert(pOp->opcode==OP_IdxLE || pOp->opcode==OP_IdxGT);
+	r.aMem = &aMem[pOp->p3];
+	for (int i = 0; i < r.nField; ++i) {
+		struct Mem *mem = &r.aMem[i];
+		enum mp_type mp_type = sql_value_type(mem);
+		enum field_type field_type = r.key_def->parts[i].type;
+		if (field_type == FIELD_TYPE_SCALAR ||
+		    mem->field_type == FIELD_TYPE_SCALAR)
+			continue;
+		bool is_nullable = r.key_def->parts[i].nullable_action ==
+				   ON_CONFLICT_ACTION_NONE;
+		if (field_mp_plain_type_is_compatible(field_type, mp_type,
+						      is_nullable))
+			continue;
+		if (!sql_type_is_numeric(field_type) ||
+		    !sql_mp_type_is_numeric(mp_type)) {
+			diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+				 mem_type_to_str(mem),
+				 field_type_strs[field_type]);
+			goto abort_due_to_error;
+		}
+	}
+	if (pOp->opcode == OP_IdxLE || pOp->opcode == OP_IdxGT)
 		r.default_rc = -1;
-	} else {
-		assert(pOp->opcode==OP_IdxGE || pOp->opcode==OP_IdxLT);
+	else
 		r.default_rc = 0;
-	}
-	r.aMem = &aMem[pOp->p3];
-#ifdef SQL_DEBUG
-	{ int i; for(i=0; i<r.nField; i++) assert(memIsValid(&r.aMem[i])); }
-#endif
-	int res =  tarantoolsqlIdxKeyCompare(pC->uc.pCursor, &r);
-	assert((OP_IdxLE&1)==(OP_IdxLT&1) && (OP_IdxGE&1)==(OP_IdxGT&1));
-	if ((pOp->opcode&1)==(OP_IdxLT&1)) {
-		assert(pOp->opcode==OP_IdxLE || pOp->opcode==OP_IdxLT);
+	int res = tarantoolsqlIdxKeyCompare(pC->uc.pCursor, &r);
+	if (pOp->opcode == OP_IdxLE || pOp->opcode == OP_IdxLT)
 		res = -res;
-	} else {
-		assert(pOp->opcode==OP_IdxGE || pOp->opcode==OP_IdxGT);
+	else
 		res++;
-	}
 	VdbeBranchTaken(res>0,2);
 	if (res>0) goto jump_to_p2;
 	break;
diff --git a/src/box/sql/vdbemem.c b/src/box/sql/vdbemem.c
index aad030d..2d10c21 100644
--- a/src/box/sql/vdbemem.c
+++ b/src/box/sql/vdbemem.c
@@ -670,6 +670,7 @@ sqlVdbeMemCast(Mem * pMem, enum field_type type)
 		return 0;
 	switch (type) {
 	case FIELD_TYPE_SCALAR:
+		pMem->field_type = FIELD_TYPE_SCALAR;
 		return 0;
 	case FIELD_TYPE_BOOLEAN:
 		if ((pMem->flags & MEM_Int) != 0) {
diff --git a/src/box/sql/where.c b/src/box/sql/where.c
index 7ec43e1..993b078 100644
--- a/src/box/sql/where.c
+++ b/src/box/sql/where.c
@@ -299,7 +299,9 @@ whereScanNext(WhereScan * pScan)
 							pX = pTerm->pExpr;
 							enum field_type expr_type =
 								expr_cmp_mutual_type(pX);
-							if (!field_type1_contains_type2(expr_type, pScan->idx_type))
+							if (!field_type1_contains_type2(expr_type, pScan->idx_type) &&
+							    !(sql_type_is_numeric(expr_type) &&
+							      sql_type_is_numeric(pScan->idx_type)))
 								continue;
 							if (pScan->is_column_seen) {
 								Parse *pParse =
diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c
index 5bc27f1..725e2af 100644
--- a/src/box/sql/wherecode.c
+++ b/src/box/sql/wherecode.c
@@ -335,72 +335,6 @@ disableTerm(WhereLevel * pLevel, WhereTerm * pTerm)
 	}
 }
 
-/**
- * Code an OP_ApplyType opcode to apply the column type string
- * @types to the n registers starting at @base.
- *
- * As an optimization, SCALAR entries (which are no-ops) at the
- * beginning and end of @types are ignored.  If all entries in
- * @types are SCALAR, then no code gets generated.
- *
- * This routine makes its own copy of @types so that the caller is
- * free to modify @types after this routine returns.
- */
-static void
-emit_apply_type(Parse *pParse, int base, int n, enum field_type *types)
-{
-	Vdbe *v = pParse->pVdbe;
-	if (types == NULL) {
-		assert(pParse->db->mallocFailed);
-		return;
-	}
-	assert(v != 0);
-
-	/*
-	 * Adjust base and n to skip over SCALAR entries at the
-	 * beginning and end of the type sequence.
-	 */
-	while (n > 0 && types[0] == FIELD_TYPE_SCALAR) {
-		n--;
-		base++;
-		types++;
-	}
-	while (n > 1 && types[n - 1] == FIELD_TYPE_SCALAR) {
-		n--;
-	}
-
-	if (n > 0) {
-		enum field_type *types_dup = field_type_sequence_dup(pParse,
-								     types, n);
-		sqlVdbeAddOp4(v, OP_ApplyType, base, n, 0,
-				  (char *) types_dup, P4_DYNAMIC);
-		sql_expr_type_cache_change(pParse, base, n);
-	}
-}
-
-/**
- * Expression @rhs, which is the RHS of a comparison operation, is
- * either a vector of n elements or, if n==1, a scalar expression.
- * Before the comparison operation, types @types are to be applied
- * to the @rhs values. This function modifies entries within the
- * field sequence to SCALAR if either:
- *
- *   * the comparison will be performed with no type, or
- *   * the type change in @types is guaranteed not to change the value.
- */
-static void
-expr_cmp_update_rhs_type(struct Expr *rhs, int n, enum field_type *types)
-{
-	for (int i = 0; i < n; i++) {
-		Expr *p = sqlVectorFieldSubexpr(rhs, i);
-		enum field_type expr_type = sql_expr_type(p);
-		if (sql_type_result(expr_type, types[i]) == FIELD_TYPE_SCALAR ||
-		    sql_expr_needs_no_type_change(p, types[i])) {
-			types[i] = FIELD_TYPE_SCALAR;
-		}
-	}
-}
-
 /*
  * Generate code for a single equality term of the WHERE clause.  An equality
  * term can be either X=expr or X IN (...).   pTerm is the term to be
@@ -644,8 +578,7 @@ static int
 codeAllEqualityTerms(Parse * pParse,	/* Parsing context */
 		     WhereLevel * pLevel,	/* Which nested loop of the FROM we are coding */
 		     int bRev,		/* Reverse the order of IN operators */
-		     int nExtraReg,	/* Number of extra registers to allocate */
-		     enum field_type **res_type)
+		     int nExtraReg)	/* Number of extra registers to allocate */
 {
 	u16 nEq;		/* The number of == or IN constraints to code */
 	u16 nSkip;		/* Number of left-most columns to skip */
@@ -669,9 +602,6 @@ codeAllEqualityTerms(Parse * pParse,	/* Parsing context */
 	nReg = pLoop->nEq + nExtraReg;
 	pParse->nMem += nReg;
 
-	enum field_type *type = sql_index_type_str(pParse->db, idx_def);
-	assert(type != NULL || pParse->db->mallocFailed);
-
 	if (nSkip) {
 		int iIdxCur = pLevel->iIdxCur;
 		sqlVdbeAddOp1(v, (bRev ? OP_Last : OP_Rewind), iIdxCur);
@@ -714,17 +644,8 @@ codeAllEqualityTerms(Parse * pParse,	/* Parsing context */
 				sqlVdbeAddOp2(v, OP_SCopy, r1, regBase + j);
 			}
 		}
-		if (pTerm->eOperator & WO_IN) {
-			if (pTerm->pExpr->flags & EP_xIsSelect) {
-				/* No type ever needs to be (or should be) applied to a value
-				 * from the RHS of an "? IN (SELECT ...)" expression. The
-				 * sqlFindInIndex() routine has already ensured that the
-				 * type of the comparison has been applied to the value.
-				 */
-				if (type != NULL)
-					type[j] = FIELD_TYPE_SCALAR;
-			}
-		} else if ((pTerm->eOperator & WO_ISNULL) == 0) {
+		if (!(pTerm->eOperator & WO_IN) &&
+		    (pTerm->eOperator & WO_ISNULL) == 0) {
 			Expr *pRight = pTerm->pExpr->pRight;
 			if (sqlExprCanBeNull(pRight)) {
 				sqlVdbeAddOp2(v, OP_IsNull, regBase + j,
@@ -733,7 +654,6 @@ codeAllEqualityTerms(Parse * pParse,	/* Parsing context */
 			}
 		}
 	}
-	*res_type = type;
 	return regBase;
 }
 
@@ -904,10 +824,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 		int iIdxCur;	/* The VDBE cursor for the index */
 		int nExtraReg = 0;	/* Number of extra registers needed */
 		int op;		/* Instruction opcode */
-		/* Types for start of range constraint. */
-		enum field_type *start_types;
-		/* Types for end of range constraint */
-		enum field_type *end_types = NULL;
 		u8 bSeekPastNull = 0;	/* True to seek past initial nulls */
 		u8 bStopAtNull = 0;	/* Add condition to terminate at NULLs */
 		int force_integer_reg = -1;  /* If non-negative: number of
@@ -994,17 +910,7 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 		 * and store the values of those terms in an array of registers
 		 * starting at regBase.
 		 */
-		regBase =
-		    codeAllEqualityTerms(pParse, pLevel, bRev, nExtraReg,
-					 &start_types);
-		if (start_types != NULL && nTop) {
-			uint32_t len = 0;
-			for (enum field_type *tmp = &start_types[nEq];
-			     *tmp != field_type_MAX; tmp++, len++);
-			uint32_t sz = len * sizeof(enum field_type);
-			end_types = sqlDbMallocRaw(db, sz);
-			memcpy(end_types, &start_types[nEq], sz);
-		}
+		regBase = codeAllEqualityTerms(pParse, pLevel, bRev, nExtraReg);
 		addrNxt = pLevel->addrNxt;
 
 		testcase(pRangeStart && (pRangeStart->eOperator & WO_LE) != 0);
@@ -1029,10 +935,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 				VdbeCoverage(v);
 			}
 
-			if (start_types) {
-				expr_cmp_update_rhs_type(pRight, nBtm,
-							 &start_types[nEq]);
-			}
 			nConstraint += nBtm;
 			testcase(pRangeStart->wtFlags & TERM_VIRTUAL);
 			if (sqlExprIsVector(pRight) == 0) {
@@ -1049,91 +951,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 		}
 		struct index_def *idx_pk = space->index[0]->def;
 		uint32_t pk_part_count = idx_pk->key_def->part_count;
-		/*
-		 * Tarantool's iterator over integer fields doesn't
-		 * tolerate floating point values. Hence, if term
-		 * is equality comparison and value of operand is
-		 * not integer, we can skip it since it always
-		 * results in false: INT a == 0.5 -> false;
-		 * It is done using OP_MustBeInt facilities.
-		 * In case term is greater comparison (a > ?), we
-		 * should notify OP_SeekGT to process truncation of
-		 * floating point value: a > 0.5 -> a >= 1;
-		 * It is done by setting P5 flag for OP_Seek*.
-		 * It is worth mentioning that we do not need
-		 * this step when it comes for less (<) comparison
-		 * of nullable field. Key is NULL in this case:
-		 * values are ordered as  NULL, ... NULL, min_value,
-		 * so to fetch min value we pass NULL to GT iterator.
-		 * The only exception is less comparison in
-		 * conjunction with ORDER BY DESC clause:
-		 * in such situation we use LE iterator and
-		 * truncated value to compare. But then
-		 * pRangeStart == NULL.
-		 * This procedure is correct for compound index:
-		 * only one comparison of less/greater type can be
-		 * used at the same time. For instance,
-		 * a < 1.5 AND b > 0.5 is handled by SeekGT using
-		 * column a and fetching column b from tuple and
-		 * OP_Le comparison.
-		 *
-		 * Note that OP_ApplyType, which is emitted before
-		 * OP_Seek** doesn't truncate floating point to
-		 * integer. That's why we need this routine.
-		 * Also, note that terms are separated by OR
-		 * predicates, so we consider term as sequence
-		 * of AND'ed predicates.
-		 */
-		size_t addrs_sz = sizeof(int) * nEq;
-		int *seek_addrs = region_alloc(&pParse->region, addrs_sz);
-		if (seek_addrs == NULL) {
-			diag_set(OutOfMemory, addrs_sz, "region", "seek_addrs");
-			pParse->is_aborted = true;
-			return 0;
-		}
-		memset(seek_addrs, 0, addrs_sz);
-		for (int i = 0; i < nEq; i++) {
-			enum field_type type = idx_def->key_def->parts[i].type;
-			if (type == FIELD_TYPE_INTEGER ||
-			    type == FIELD_TYPE_UNSIGNED) {
-				/*
-				 * OP_MustBeInt consider NULLs as
-				 * non-integer values, so firstly
-				 * check whether value is NULL or not.
-				 */
-				seek_addrs[i] = sqlVdbeAddOp1(v, OP_IsNull,
-							      regBase);
-				sqlVdbeAddOp2(v, OP_MustBeInt, regBase + i,
-					      addrNxt);
-				start_types[i] = FIELD_TYPE_SCALAR;
-				/*
-				 * We need to notify column cache
-				 * that type of value may change
-				 * so we should fetch value from
-				 * tuple again rather then copy
-				 * from register.
-				 */
-				sql_expr_type_cache_change(pParse, regBase + i,
-							   1);
-			}
-		}
-		/* Inequality constraint comes always at the end of list. */
-		part_count = idx_def->key_def->part_count;
-		if (pRangeStart != NULL) {
-			/*
-			 * nEq == 0 means that filter condition
-			 * contains only inequality.
-			 */
-			uint32_t ineq_idx = nEq == 0 ? 0 : nEq - 1;
-			assert(ineq_idx < part_count);
-			enum field_type ineq_type =
-				idx_def->key_def->parts[ineq_idx].type;
-			if (ineq_type == FIELD_TYPE_INTEGER ||
-			    ineq_type == FIELD_TYPE_UNSIGNED)
-				force_integer_reg = regBase + nEq;
-		}
-		emit_apply_type(pParse, regBase, nConstraint - bSeekPastNull,
-				start_types);
 		if (pLoop->nSkip > 0 && nConstraint == pLoop->nSkip) {
 			/* The skip-scan logic inside the call to codeAllEqualityConstraints()
 			 * above has already left the cursor sitting on the correct row,
@@ -1143,10 +960,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 			op = aStartOp[(start_constraints << 2) +
 				      (startEq << 1) + bRev];
 			assert(op != 0);
-			for (uint32_t i = 0; i < nEq; ++i) {
-				if (seek_addrs[i] != 0)
-					sqlVdbeJumpHere(v, seek_addrs[i]);
-			}
 			sqlVdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase,
 					     nConstraint);
 			/* If this is Seek* opcode, and IPK is detected in the
@@ -1186,13 +999,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 						  addrNxt);
 				VdbeCoverage(v);
 			}
-			if (end_types) {
-				expr_cmp_update_rhs_type(pRight, nTop, end_types);
-				emit_apply_type(pParse, regBase + nEq, nTop,
-						end_types);
-			} else {
-				assert(pParse->db->mallocFailed);
-			}
 			nConstraint += nTop;
 			testcase(pRangeEnd->wtFlags & TERM_VIRTUAL);
 
@@ -1206,8 +1012,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 			endEq = 0;
 			nConstraint++;
 		}
-		sqlDbFree(db, start_types);
-		sqlDbFree(db, end_types);
 
 		/* Top of the loop body */
 		pLevel->p2 = sqlVdbeCurrentAddr(v);
diff --git a/src/box/tuple_compare.cc b/src/box/tuple_compare.cc
index 3f8a0ce..6cbf555 100644
--- a/src/box/tuple_compare.cc
+++ b/src/box/tuple_compare.cc
@@ -104,6 +104,12 @@ mp_classof(enum mp_type type)
 	return mp_classes[type];
 }
 
+int
+mp_type_classes_comp(enum mp_type ltype, enum mp_type rtype)
+{
+	return mp_classof(ltype) - mp_classof(rtype);
+}
+
 static enum mp_class
 mp_extension_class(const char *data)
 {
diff --git a/src/box/tuple_compare.h b/src/box/tuple_compare.h
index 8614f23..0c1e4c6 100644
--- a/src/box/tuple_compare.h
+++ b/src/box/tuple_compare.h
@@ -31,6 +31,7 @@
  * SUCH DAMAGE.
  */
 #include <stdint.h>
+#include <msgpuck.h>
 
 #if defined(__cplusplus)
 extern "C" {
@@ -76,6 +77,14 @@ typedef uint64_t hint_t;
 void
 key_def_set_compare_func(struct key_def *def);
 
+/**
+ * Return an integer less than, equal to, or greater than zero if
+ * mp_class of ltype is found, respectively, to be less than, to
+ * match, or be greater than mp_class of rtype.
+ */
+int
+mp_type_classes_comp(enum mp_type ltype, enum mp_type rtype);
+
 #if defined(__cplusplus)
 } /* extern "C" */
 #endif /* defined(__cplusplus) */
diff --git a/test/sql-tap/identifier_case.test.lua b/test/sql-tap/identifier_case.test.lua
index 2a00626..242645f 100755
--- a/test/sql-tap/identifier_case.test.lua
+++ b/test/sql-tap/identifier_case.test.lua
@@ -242,11 +242,11 @@ data = {
     { 2,  [[ 'a' < 'b' collate "binary" ]], {0, {true}}},
     { 3,  [[ 'a' < 'b' collate 'binary' ]], {1, [[Syntax error at line 1 near ''binary'']]}},
     { 4,  [[ 'a' < 'b' collate "unicode" ]], {0, {true}}},
-    { 5,  [[ 5 < 'b' collate "unicode" ]], {0, {true}}},
+    { 5,  [[ 5 < 'b' collate "unicode" ]], {1, "Type mismatch: can not convert text to unsigned"}},
     { 6,  [[ 5 < 'b' collate unicode ]], {1,"Collation 'UNICODE' does not exist"}},
-    { 7,  [[ 5 < 'b' collate "unicode_ci" ]], {0, {true}}},
+    { 7,  [[ 5 < 'b' collate "unicode_ci" ]], {1, "Type mismatch: can not convert text to unsigned"}},
     { 8,  [[ 5 < 'b' collate NONE ]], {1, "Collation 'NONE' does not exist"}},
-    { 9,  [[ 5 < 'b' collate "none" ]], {0, {true}}},
+    { 9,  [[ 5 < 'b' collate "none" ]], {1, "Type mismatch: can not convert text to unsigned"}},
 }
 
 for _, row in ipairs(data) do
diff --git a/test/sql-tap/in1.test.lua b/test/sql-tap/in1.test.lua
index 570cc17..710dd80 100755
--- a/test/sql-tap/in1.test.lua
+++ b/test/sql-tap/in1.test.lua
@@ -633,16 +633,12 @@ test:do_execsql_test(
         -- </in-11.1>
     })
 
-test:do_test(
-    "in-11.2",
-    function()
-        -- The '2' should be coerced into 2 because t6.b is NUMERIC
-        return test:execsql [[
-            SELECT * FROM t6 WHERE b IN ('2');
-        ]]
-    end, {
+test:do_catchsql_test(
+    "in-11.2",[[
+        SELECT * FROM t6 WHERE b IN ('2');
+    ]], {
         -- <in-11.2>
-        1, 2
+        1, "Type mismatch: can not convert text to unsigned"
         -- </in-11.2>
     })
 
diff --git a/test/sql-tap/in4.test.lua b/test/sql-tap/in4.test.lua
index 8c69173..4d400ce 100755
--- a/test/sql-tap/in4.test.lua
+++ b/test/sql-tap/in4.test.lua
@@ -147,13 +147,13 @@ test:do_execsql_test(
         -- </in4-2.7>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "in4-2.8",
     [[
         SELECT b FROM t2 WHERE a IN ('', '0.0.0', '2') 
     ]], {
         -- <in4-2.8>
-        "two"
+        1, "Type mismatch: can not convert text to integer"
         -- </in4-2.8>
     })
 
@@ -585,7 +585,7 @@ test:do_execsql_test(
         -- </in4-4.6>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "in4-4.11",
     [[
         CREATE TABLE t4b(a TEXT, b NUMBER, c  INT PRIMARY KEY);
@@ -593,87 +593,87 @@ test:do_execsql_test(
         SELECT c FROM t4b WHERE a=b;
     ]], {
         -- <in4-4.11>
-        4
+        1, "Type mismatch: can not convert unsigned to text"
         -- </in4-4.11>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "in4-4.12",
     [[
         SELECT c FROM t4b WHERE b=a;
     ]], {
         -- <in4-4.12>
-        4
+        1, "Type mismatch: can not convert text to unsigned"
         -- </in4-4.12>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "in4-4.13",
     [[
         SELECT c FROM t4b WHERE +a=b;
     ]], {
         -- <in4-4.13>
-        4
+        1, "Type mismatch: can not convert text to unsigned"
         -- </in4-4.13>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "in4-4.14",
     [[
         SELECT c FROM t4b WHERE a=+b;
     ]], {
         -- <in4-4.14>
-        4
+        1, "Type mismatch: can not convert unsigned to text"
         -- </in4-4.14>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "in4-4.15",
     [[
         SELECT c FROM t4b WHERE +b=a;
     ]], {
         -- <in4-4.15>
-        4
+        1, "Type mismatch: can not convert unsigned to text"
         -- </in4-4.15>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "in4-4.16",
     [[
         SELECT c FROM t4b WHERE b=+a;
     ]], {
         -- <in4-4.16>
-        4
+        1, "Type mismatch: can not convert text to unsigned"
         -- </in4-4.16>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "in4-4.17",
     [[
         SELECT c FROM t4b WHERE a IN (b);
     ]], {
         -- <in4-4.17>
-        4
+        1, "Type mismatch: can not convert unsigned to text"
         -- </in4-4.17>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "in4-4.18",
     [[
         SELECT c FROM t4b WHERE b IN (a);
     ]], {
         -- <in4-4.18>
-        4
+        1, "Type mismatch: can not convert text to unsigned"
         -- </in4-4.18>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "in4-4.19",
     [[
         SELECT c FROM t4b WHERE +b IN (a);
     ]], {
         -- <in4-4.19>
-        4
+        1, "Type mismatch: can not convert unsigned to text"
         -- </in4-4.19>
     })
 
diff --git a/test/sql-tap/index1.test.lua b/test/sql-tap/index1.test.lua
index e173e68..85988c9 100755
--- a/test/sql-tap/index1.test.lua
+++ b/test/sql-tap/index1.test.lua
@@ -785,7 +785,7 @@ test:do_catchsql_test(
         SELECT c FROM t6 WHERE a>123;
     ]], {
         -- <index-14.6>
-        1, "Type mismatch: can not convert  to numeric"
+        1, "Type mismatch: can not convert unsigned to text"
         -- </index-14.6>
     })
 
@@ -795,7 +795,7 @@ test:do_catchsql_test(
         SELECT c FROM t6 WHERE a>=123;
     ]], {
         -- <index-14.7>
-        1, "Type mismatch: can not convert  to numeric"
+        1, "Type mismatch: can not convert unsigned to text"
         -- </index-14.7>
     })
 
diff --git a/test/sql-tap/insert3.test.lua b/test/sql-tap/insert3.test.lua
index 43bb066..ff8f6de 100755
--- a/test/sql-tap/insert3.test.lua
+++ b/test/sql-tap/insert3.test.lua
@@ -59,7 +59,7 @@ test:do_execsql_test(
     [[
             CREATE TABLE log2(rowid INTEGER PRIMARY KEY AUTOINCREMENT, x TEXT UNIQUE,y INT );
             CREATE TRIGGER r2 BEFORE INSERT ON t1 FOR EACH ROW BEGIN
-              UPDATE log2 SET y=y+1 WHERE x=new.b;
+              UPDATE log2 SET y=y+1 WHERE x=CAST(new.b AS STRING);
               INSERT OR IGNORE INTO log2(x, y) VALUES(new.b,1);
             END;
             INSERT INTO t1(a, b) VALUES('hi', 453);
diff --git a/test/sql-tap/intpkey.test.lua b/test/sql-tap/intpkey.test.lua
index bec2670..71739f7 100755
--- a/test/sql-tap/intpkey.test.lua
+++ b/test/sql-tap/intpkey.test.lua
@@ -859,30 +859,30 @@ test:do_execsql_test(
         -- </intpkey-14.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "intpkey-14.3",
     [[
         SELECT * FROM t3 WHERE a>'2';
     ]], {
         -- <intpkey-14.3>
-        3, 3, "3"
+        1, "Type mismatch: can not convert text to integer"
         -- </intpkey-14.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "intpkey-14.4",
     [[
         SELECT * FROM t3 WHERE a<'2';
     ]], {
         -- <intpkey-14.4>
-        1, 1, "one"
+        1, "Type mismatch: can not convert text to integer"
         -- </intpkey-14.4>
     })
 
 test:do_execsql_test(
     "intpkey-14.5",
     [[
-        SELECT * FROM t3 WHERE a<c;
+        SELECT * FROM t3 WHERE CAST(a AS TEXT)<c;
     ]], {
         -- <intpkey-14.5>
         1, 1, "one"
@@ -892,7 +892,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "intpkey-14.6",
     [[
-        SELECT * FROM t3 WHERE a=c;
+        SELECT * FROM t3 WHERE CAST(a AS TEXT)=c;
     ]], {
         -- <intpkey-14.6>
         2, 2, "2", 3, 3, "3"
diff --git a/test/sql-tap/join.test.lua b/test/sql-tap/join.test.lua
index 4f014e0..577db7a 100755
--- a/test/sql-tap/join.test.lua
+++ b/test/sql-tap/join.test.lua
@@ -1028,23 +1028,23 @@ test:do_test(
         -- </join-11.8>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "join-11.9",
     [[
         SELECT * FROM t1 NATURAL JOIN t2 
     ]], {
         -- <join-11.9>
-        "one", "1.0", "two", "2"
+        1, "Type mismatch: can not convert text to integer"
         -- </join-11.9>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "join-11.10",
     [[
         SELECT * FROM t2 NATURAL JOIN t1 
     ]], {
         -- <join-11.10>
-        1, "one", 2, "two"
+        1, "Type mismatch: can not convert text to unsigned"
         -- </join-11.10>
     })
 
diff --git a/test/sql-tap/misc1.test.lua b/test/sql-tap/misc1.test.lua
index 32f38cc..4f83bc1 100755
--- a/test/sql-tap/misc1.test.lua
+++ b/test/sql-tap/misc1.test.lua
@@ -88,7 +88,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "misc1-1.4",
     [[
-        SELECT x75 FROM manycol WHERE x50=350
+        SELECT x75 FROM manycol WHERE x50='350'
     ]], {
         -- <misc1-1.4>
         "375"
@@ -98,7 +98,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "misc1-1.5",
     [[
-        SELECT x50 FROM manycol WHERE x99=599
+        SELECT x50 FROM manycol WHERE x99='599'
     ]], {
         -- <misc1-1.5>
         "550"
@@ -109,7 +109,7 @@ test:do_test(
     "misc1-1.6",
     function()
         test:execsql("CREATE INDEX manycol_idx1 ON manycol(x99)")
-        return test:execsql("SELECT x50 FROM manycol WHERE x99=899")
+        return test:execsql("SELECT x50 FROM manycol WHERE x99='899'")
     end, {
         -- <misc1-1.6>
         "850"
@@ -129,7 +129,7 @@ test:do_execsql_test(
 test:do_test(
     "misc1-1.8",
     function()
-        test:execsql("DELETE FROM manycol WHERE x98=1234")
+        test:execsql("DELETE FROM manycol WHERE x98='1234'")
         return test:execsql("SELECT count(*) FROM manycol")
     end, {
         -- <misc1-1.8>
@@ -140,7 +140,7 @@ test:do_test(
 test:do_test(
     "misc1-1.9",
     function()
-        test:execsql("DELETE FROM manycol WHERE x98=998")
+        test:execsql("DELETE FROM manycol WHERE x98='998'")
         return test:execsql("SELECT count(*) FROM manycol")
     end, {
         -- <misc1-1.9>
@@ -151,7 +151,7 @@ test:do_test(
 test:do_test(
     "misc1-1.10",
     function()
-        test:execsql("DELETE FROM manycol WHERE x99=500")
+        test:execsql("DELETE FROM manycol WHERE x99='500'")
         return test:execsql("SELECT count(*) FROM manycol")
     end, {
         -- <misc1-1.10>
@@ -162,7 +162,7 @@ test:do_test(
 test:do_test(
     "misc1-1.11",
     function()
-        test:execsql("DELETE FROM manycol WHERE x99=599")
+        test:execsql("DELETE FROM manycol WHERE x99='599'")
         return test:execsql("SELECT count(*) FROM manycol")
     end, {
         -- <misc1-1.11>
@@ -479,9 +479,9 @@ local where = ""
 test:do_test(
     "misc1-10.1",
     function()
-        where = "WHERE x0>=0"
+        where = "WHERE x0>='0'"
         for i = 1, 99, 1 do
-            where = where .. " AND x"..i.."<>0"
+            where = where .. " AND x"..i.."<>'0'"
         end
         return test:catchsql("SELECT count(*) FROM manycol "..where.."")
     end, {
@@ -496,7 +496,7 @@ test:do_test(
 test:do_test(
     "misc1-10.3",
     function()
-        where = string.gsub(where,"x0>=0", "x0=0")
+        where = string.gsub(where,"x0>='0'", "x0='0'")
         return test:catchsql("DELETE FROM manycol "..where.."")
     end, {
         -- <misc1-10.3>
@@ -520,7 +520,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "misc1-10.6",
     [[
-        SELECT x1 FROM manycol WHERE x0=100
+        SELECT x1 FROM manycol WHERE x0='100'
     ]], {
         -- <misc1-10.6>
         "101"
@@ -530,7 +530,7 @@ test:do_execsql_test(
 test:do_test(
     "misc1-10.7",
     function()
-        where = string.gsub(where, "x0=0", "x0=100")
+        where = string.gsub(where, "x0='0'", "x0='100'")
         return test:catchsql("UPDATE manycol SET x1=x1+1 "..where.."")
     end, {
         -- <misc1-10.7>
@@ -541,7 +541,7 @@ test:do_test(
 test:do_execsql_test(
     "misc1-10.8",
     [[
-        SELECT x1 FROM manycol WHERE x0=100
+        SELECT x1 FROM manycol WHERE x0='100'
     ]], {
         -- <misc1-10.8>
         "102"
@@ -563,7 +563,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "misc1-10.10",
     [[
-        SELECT x1 FROM manycol WHERE x0=100
+        SELECT x1 FROM manycol WHERE x0='100'
     ]], {
         -- <misc1-10.10>
         "103"
@@ -619,13 +619,13 @@ test:do_execsql_test(
         -- </misc1-12.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "misc1-12.2",
     [[
         SELECT '0'==0.0
     ]], {
         -- <misc1-12.2>
-        true
+        1, "Type mismatch: can not convert real to text"
         -- </misc1-12.2>
     })
 
diff --git a/test/sql-tap/select1.test.lua b/test/sql-tap/select1.test.lua
index fbebfab..ed01c26 100755
--- a/test/sql-tap/select1.test.lua
+++ b/test/sql-tap/select1.test.lua
@@ -320,7 +320,7 @@ test:do_catchsql_test(
         SELECT count(*),count(a),count(b) FROM t4 WHERE b=5
     ]], {
         -- <select1-2.5.3>
-        1, "Type mismatch: can not convert This is a string that is too big to fit inside a NBFS buffer to numeric"
+        1, "Type mismatch: can not convert unsigned to text"
         -- </select1-2.5.3>
     })
 
@@ -1909,23 +1909,23 @@ test:do_execsql_test(
 
 
 -- ifcapable compound
-test:do_execsql_test(
+test:do_catchsql_test(
         "select1-12.7",
         [[
             SELECT * FROM t3 WHERE a=(SELECT 1);
         ]], {
             -- <select1-12.7>
-            0, "1", "2"
+            1, "Type mismatch: can not convert unsigned to text"
             -- </select1-12.7>
         })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "select1-12.8",
     [[
         SELECT * FROM t3 WHERE a=(SELECT 2);
     ]], {
         -- <select1-12.8>
-
+        1, "Type mismatch: can not convert unsigned to text"
         -- </select1-12.8>
     })
 
diff --git a/test/sql-tap/select7.test.lua b/test/sql-tap/select7.test.lua
index fec5d7a..167ce05 100755
--- a/test/sql-tap/select7.test.lua
+++ b/test/sql-tap/select7.test.lua
@@ -256,7 +256,7 @@ test:do_execsql_test(
         DROP TABLE IF EXISTS t5;
         CREATE TABLE t5(a TEXT primary key, b INT);
         INSERT INTO t5 VALUES(123, 456);
-        SELECT typeof(a), a FROM t5 GROUP BY a HAVING a<b;
+        SELECT typeof(a), a FROM t5 GROUP BY a HAVING a < CAST(b AS STRING);
     ]], {
         -- <select7-7.7>
         "string", "123"
diff --git a/test/sql-tap/sql-errors.test.lua b/test/sql-tap/sql-errors.test.lua
index 5ec94bf..8ea6f8b 100755
--- a/test/sql-tap/sql-errors.test.lua
+++ b/test/sql-tap/sql-errors.test.lua
@@ -765,7 +765,7 @@ test:do_catchsql_test(
 		SELECT X'ff' >= false;
 	]], {
 		-- <sql-errors-2.8>
-		1, "Type mismatch: can not convert varbinary to boolean"
+		1, "Type mismatch: can not convert boolean to varbinary"
 		-- </sql-errors-2.8>
 	})
 
@@ -775,7 +775,7 @@ test:do_catchsql_test(
 		SELECT X'ff' <= false;
 	]], {
 		-- <sql-errors-2.9>
-		1, "Type mismatch: can not convert varbinary to boolean"
+		1, "Type mismatch: can not convert boolean to varbinary"
 		-- </sql-errors-2.9>
 	})
 
diff --git a/test/sql-tap/subquery.test.lua b/test/sql-tap/subquery.test.lua
index 6bedf58..4a59b01 100755
--- a/test/sql-tap/subquery.test.lua
+++ b/test/sql-tap/subquery.test.lua
@@ -284,13 +284,13 @@ test:do_execsql_test(
         -- </subquery-2.3.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "subquery-2.3.2",
     [[
         SELECT a IN (10.0, 20) FROM t3;
     ]], {
         -- <subquery-2.3.2>
-        false
+        1, "Type mismatch: can not convert text to real"
         -- </subquery-2.3.2>
     })
 
diff --git a/test/sql-tap/tkt-9a8b09f8e6.test.lua b/test/sql-tap/tkt-9a8b09f8e6.test.lua
index db0881c..e80e7c6 100755
--- a/test/sql-tap/tkt-9a8b09f8e6.test.lua
+++ b/test/sql-tap/tkt-9a8b09f8e6.test.lua
@@ -83,23 +83,23 @@ test:do_execsql_test(
         -- </1.5>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     2.1,
     [[
         SELECT x FROM t1 WHERE x IN (1);
     ]], {
         -- <2.1>
-        "1"
+        1, "Type mismatch: can not convert unsigned to text"
         -- </2.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     2.2,
     [[
         SELECT x FROM t1 WHERE x IN (1.0);
     ]], {
         -- <2.2>
-        "1"
+        1, "Type mismatch: can not convert real to text"
         -- </2.2>
     })
 
@@ -123,23 +123,23 @@ test:do_execsql_test(
         -- </2.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     2.5,
     [[
         SELECT x FROM t1 WHERE 1 IN (x);
     ]], {
         -- <2.5>
-        "1"
+        1, "Type mismatch: can not convert unsigned to text"
         -- </2.5>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     2.6,
     [[
         SELECT x FROM t1 WHERE 1.0 IN (x);
     ]], {
         -- <2.6>
-        "1"
+        1, "Type mismatch: can not convert real to text"
         -- </2.6>
     })
 
@@ -183,23 +183,23 @@ test:do_execsql_test(
         -- </3.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     3.3,
     [[
         SELECT x FROM t2 WHERE x IN ('1');
     ]], {
         -- <3.3>
-        1
+        1, "Type mismatch: can not convert text to integer"
         -- </3.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     3.4,
     [[
         SELECT x FROM t2 WHERE x IN ('1.0');
     ]], {
         -- <3.4>
-        1
+        1, "Type mismatch: can not convert text to integer"
         -- </3.4>
     })
 
@@ -223,23 +223,23 @@ test:do_execsql_test(
         -- </3.6>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     3.7,
     [[
         SELECT x FROM t2 WHERE '1' IN (x);
     ]], {
         -- <3.7>
-        1
+        1, "Type mismatch: can not convert text to integer"
         -- </3.7>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     3.8,
     [[
         SELECT x FROM t2 WHERE '1.0' IN (x);
     ]], {
         -- <3.8>
-        1
+        1, "Type mismatch: can not convert text to integer"
         -- </3.8>
     })
 
@@ -263,23 +263,23 @@ test:do_execsql_test(
         -- </4.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     4.3,
     [[
         SELECT x FROM t3 WHERE x IN ('1');
     ]], {
         -- <4.3>
-        1.0
+        1, "Type mismatch: can not convert text to number"
         -- </4.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     4.4,
     [[
         SELECT x FROM t3 WHERE x IN ('1.0');
     ]], {
         -- <4.4>
-        1.0
+        1, "Type mismatch: can not convert text to number"
         -- </4.4>
     })
 
@@ -303,23 +303,23 @@ test:do_execsql_test(
         -- </4.6>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     4.7,
     [[
         SELECT x FROM t3 WHERE '1' IN (x);
     ]], {
         -- <4.7>
-        1
+        1, "Type mismatch: can not convert text to number"
         -- </4.7>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     4.8,
     [[
         SELECT x FROM t3 WHERE '1.0' IN (x);
     ]], {
         -- <4.8>
-        1
+        1, "Type mismatch: can not convert text to number"
         -- </4.8>
     })
 
@@ -343,23 +343,23 @@ test:do_execsql_test(
         -- </5.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     5.3,
     [[
         SELECT x FROM t4 WHERE x IN ('1');
     ]], {
         -- <5.3>
-        
+        1, "Type mismatch: can not convert text to number"
         -- </5.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     5.4,
     [[
         SELECT x FROM t4 WHERE x IN ('1.0');
     ]], {
         -- <5.4>
-        
+        1, "Type mismatch: can not convert text to number"
         -- </5.4>
     })
 
@@ -373,13 +373,13 @@ test:do_execsql_test(
         -- </5.5>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     5.6,
     [[
         SELECT x FROM t4 WHERE x IN ('1.11');
     ]], {
         -- <5.6>
-        1.11
+        1, "Type mismatch: can not convert text to number"
         -- </5.6>
     })
 
@@ -403,23 +403,23 @@ test:do_execsql_test(
         -- </5.8>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     5.9,
     [[
         SELECT x FROM t4 WHERE '1' IN (x);
     ]], {
         -- <5.9>
-        
+        1, "Type mismatch: can not convert text to number"
         -- </5.9>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     5.10,
     [[
         SELECT x FROM t4 WHERE '1.0' IN (x);
     ]], {
         -- <5.10>
-        
+        1, "Type mismatch: can not convert text to number"
         -- </5.10>
     })
 
@@ -433,13 +433,13 @@ test:do_execsql_test(
         -- </5.11>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     5.12,
     [[
         SELECT x FROM t4 WHERE '1.11' IN (x);
     ]], {
         -- <5.12>
-        1.11
+        1, "Type mismatch: can not convert text to number"
         -- </5.12>
     })
 
@@ -463,23 +463,23 @@ test:do_execsql_test(
         -- </6.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     6.3,
     [[
         SELECT x, y FROM t5 WHERE x IN ('1');
     ]], {
         -- <6.3>
-        1, "one", 1, "two", 1, "three", 1.0, "four"
+        1, "Type mismatch: can not convert text to unsigned"
         -- </6.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     6.4,
     [[
         SELECT x, y FROM t5 WHERE x IN ('1.0');
     ]], {
         -- <6.4>
-        1, "one", 1, "two", 1, "three", 1.0, "four"
+        1, "Type mismatch: can not convert text to unsigned"
         -- </6.4>
     })
 
@@ -503,23 +503,23 @@ test:do_execsql_test(
         -- </6.6>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     6.7,
     [[
         SELECT x, y FROM t5 WHERE '1' IN (x);
     ]], {
         -- <6.7>
-        1, "one", 1, "two", 1, "three", 1.0, "four"
+        1, "Type mismatch: can not convert text to unsigned"
         -- </6.7>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     6.8,
     [[
         SELECT x, y FROM t5 WHERE '1.0' IN (x);
     ]], {
         -- <6.8>
-        1, "one", 1, "two", 1, "three", 1, "four"
+        1, "Type mismatch: can not convert text to unsigned"
         -- </6.8>
     })
 
diff --git a/test/sql-tap/tkt-f973c7ac31.test.lua b/test/sql-tap/tkt-f973c7ac31.test.lua
index 82bdb52..6bf7884 100755
--- a/test/sql-tap/tkt-f973c7ac31.test.lua
+++ b/test/sql-tap/tkt-f973c7ac31.test.lua
@@ -20,7 +20,7 @@ test:plan(21)
 test:do_execsql_test(
     "tkt-f973c7ac3-1.0",
     [[
-        CREATE TABLE t(id INT primary key, c1 INTEGER, c2 INTEGER);
+        CREATE TABLE t(id INT primary key, c1 UNSIGNED, c2 UNSIGNED);
         INSERT INTO t VALUES(1, 5, 5);
         INSERT INTO t VALUES(2, 5, 4);
     ]], {
@@ -36,12 +36,12 @@ local sqls = {
 
 for tn, sql in ipairs(sqls) do
     test:execsql(sql)
-    test:do_execsql_test(
+    test:do_catchsql_test(
         "tkt-f973c7ac3-1."..tn..".1",
         [[
             SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND c2<='2' ORDER BY c2 DESC 
         ]], {
-            
+            1,"Type mismatch: can not convert text to unsigned"
         })
 
     test:do_execsql_test(
@@ -52,36 +52,36 @@ for tn, sql in ipairs(sqls) do
             5, 5, 5, 4
         })
 
-    test:do_execsql_test(
+    test:do_catchsql_test(
         "tkt-f973c7ac3-1."..tn..".3",
         [[
             SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND c2<='5' ORDER BY c2 DESC 
         ]], {
-            5, 5, 5, 4
+            1,"Type mismatch: can not convert text to unsigned"
         })
 
-    test:do_execsql_test(
+    test:do_catchsql_test(
         "tkt-f973c7ac3-1."..tn..".4",
         [[
             SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>'0' AND c2<=5 ORDER BY c2 DESC 
         ]], {
-            5, 5, 5, 4
+            1,"Type mismatch: can not convert text to unsigned"
         })
 
-    test:do_execsql_test(
+    test:do_catchsql_test(
         "tkt-f973c7ac3-1."..tn..".5",
         [[
             SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>'0' AND c2<='5' ORDER BY c2 DESC 
         ]], {
-            5, 5, 5, 4
+            1,"Type mismatch: can not convert text to unsigned"
         })
 
-    test:do_execsql_test(
+    test:do_catchsql_test(
         "tkt-f973c7ac3-1."..tn..".6",
         [[
             SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND c2<='2' ORDER BY c2 ASC 
         ]], {
-            
+            1,"Type mismatch: can not convert text to unsigned"
         })
 
     test:do_execsql_test(
@@ -92,28 +92,28 @@ for tn, sql in ipairs(sqls) do
             5, 4, 5, 5
         })
 
-    test:do_execsql_test(
+    test:do_catchsql_test(
         "tkt-f973c7ac3-1."..tn..".8",
         [[
             SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND c2<='5' ORDER BY c2 ASC 
         ]], {
-            5, 4, 5, 5
+            1,"Type mismatch: can not convert text to unsigned"
         })
 
-    test:do_execsql_test(
+    test:do_catchsql_test(
         "tkt-f973c7ac3-1."..tn..".9",
         [[
             SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>'0' AND c2<=5 ORDER BY c2 ASC 
         ]], {
-            5, 4, 5, 5
+            1,"Type mismatch: can not convert text to unsigned"
         })
 
-    test:do_execsql_test(
+    test:do_catchsql_test(
         "tkt-f973c7ac3-1."..tn..".10",
         [[
             SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>'0' AND c2<='5' ORDER BY c2 ASC 
         ]], {
-            5, 4, 5, 5
+            1,"Type mismatch: can not convert text to unsigned"
         })
 
 end
diff --git a/test/sql-tap/tkt-fc7bd6358f.test.lua b/test/sql-tap/tkt-fc7bd6358f.test.lua
index fe5d620..8b99f8e 100755
--- a/test/sql-tap/tkt-fc7bd6358f.test.lua
+++ b/test/sql-tap/tkt-fc7bd6358f.test.lua
@@ -78,17 +78,17 @@ for a, from in ipairs(froms) do
         test:do_test(
             string.format("tkt-fc7bd6358f.110.%s.%s.1", a, b),
             function()
-                return test:execsql(string.format("SELECT t1.textid, i.intid, t2.textid %s %s", from, where))
+                return test:catchsql(string.format("SELECT t1.textid, i.intid, t2.textid %s %s", from, where))
             end, {
-                "12", 12, "12", "34", 34, "34"
+                1, "Type mismatch: can not convert text to integer"
             })
 
         test:do_test(
             string.format("tkt-fc7bd6358f.110.%s.%s.2", a, b),
             function()
-                return test:execsql(string.format("SELECT t1.textid, i.intid, t2.textid %s %s", from, where))
+                return test:catchsql(string.format("SELECT t1.textid, i.intid, t2.textid %s %s", from, where))
             end, {
-                "12", 12, "12", "34", 34, "34"
+                1, "Type mismatch: can not convert text to integer"
             })
 
     end
diff --git a/test/sql-tap/tkt3493.test.lua b/test/sql-tap/tkt3493.test.lua
index 7ceec47..e5d7b2f 100755
--- a/test/sql-tap/tkt3493.test.lua
+++ b/test/sql-tap/tkt3493.test.lua
@@ -45,7 +45,7 @@ test:do_execsql_test(
     [[
         SELECT 
           CASE 
-             WHEN B.val = 1 THEN 'XYZ' 
+             WHEN B.val = '1' THEN 'XYZ' 
              ELSE A.val 
           END AS Col1
         FROM B  
@@ -63,7 +63,7 @@ test:do_execsql_test(
     [[
         SELECT DISTINCT
           CASE 
-             WHEN B.val = 1 THEN 'XYZ' 
+             WHEN B.val = '1' THEN 'XYZ'
              ELSE A.val 
           END AS Col1
         FROM B  
@@ -79,7 +79,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-1.4",
     [[
-        SELECT b.val, CASE WHEN b.val = 1 THEN 'xyz' ELSE b.val END AS col1 FROM b;
+        SELECT b.val, CASE WHEN b.val = '1' THEN 'xyz' ELSE b.val END AS col1 FROM b;
     ]], {
         -- <tkt3493-1.4>
         "1", "xyz", "2", "2"
@@ -91,7 +91,7 @@ test:do_execsql_test(
     [[
         SELECT DISTINCT 
           b.val, 
-          CASE WHEN b.val = 1 THEN 'xyz' ELSE b.val END AS col1 
+          CASE WHEN b.val = '1' THEN 'xyz' ELSE b.val END AS col1
         FROM b;
     ]], {
         -- <tkt3493-1.5>
@@ -126,7 +126,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.2.1",
     [[
-        SELECT a=123 FROM t1 GROUP BY a 
+        SELECT a = '123' FROM t1 GROUP BY a;
     ]], {
         -- <tkt3493-2.2.1>
         true
@@ -136,7 +136,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.2.2",
     [[
-        SELECT a=123 FROM t1 
+        SELECT a = '123' FROM t1;
     ]], {
         -- <tkt3493-2.2.2>
         true
@@ -156,7 +156,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.2.4",
     [[
-        SELECT count(*), a=123 FROM t1 
+        SELECT count(*), a = '123' FROM t1;
     ]], {
         -- <tkt3493-2.2.4>
         1, true
@@ -166,7 +166,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.2.5",
     [[
-        SELECT count(*), +a=123 FROM t1 
+        SELECT count(*), +a = '123' FROM t1;
     ]], {
         -- <tkt3493-2.2.5>
         1, true
@@ -176,7 +176,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.3.3",
     [[
-        SELECT b='456' FROM t1 GROUP BY a 
+        SELECT b = 456 FROM t1 GROUP BY a;
     ]], {
         -- <tkt3493-2.3.3>
         true
@@ -186,7 +186,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.3.1",
     [[
-        SELECT b='456' FROM t1 GROUP BY b 
+        SELECT b = 456 FROM t1 GROUP BY b;
     ]], {
         -- <tkt3493-2.3.1>
         true
@@ -196,7 +196,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.3.2",
     [[
-        SELECT b='456' FROM t1 
+        SELECT b = 456 FROM t1;
     ]], {
         -- <tkt3493-2.3.2>
         true
@@ -206,7 +206,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.4.1",
     [[
-        SELECT typeof(a), a FROM t1 GROUP BY a HAVING a=123 
+        SELECT typeof(a), a FROM t1 GROUP BY a HAVING a = '123';
     ]], {
         -- <tkt3493-2.4.1>
         "string", "123"
@@ -216,7 +216,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.4.2",
     [[
-        SELECT typeof(a), a FROM t1 GROUP BY b HAVING a=123 
+        SELECT typeof(a), a FROM t1 GROUP BY b HAVING a = '123';
     ]], {
         -- <tkt3493-2.4.2>
         "string", "123"
@@ -226,7 +226,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.5.1",
     [[
-        SELECT typeof(b), b FROM t1 GROUP BY a HAVING b='456' 
+        SELECT typeof(b), b FROM t1 GROUP BY a HAVING b = 456;
     ]], {
         -- <tkt3493-2.5.1>
         "integer", 456
@@ -236,7 +236,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.5.2",
     [[
-        SELECT typeof(b), b FROM t1 GROUP BY b HAVING b='456' 
+        SELECT typeof(b), b FROM t1 GROUP BY b HAVING b = 456;
     ]], {
         -- <tkt3493-2.5.2>
         "integer", 456
diff --git a/test/sql-tap/transitive1.test.lua b/test/sql-tap/transitive1.test.lua
index e960565..cc7e066 100755
--- a/test/sql-tap/transitive1.test.lua
+++ b/test/sql-tap/transitive1.test.lua
@@ -63,7 +63,7 @@ test:do_execsql_test(
         INSERT INTO t2 VALUES(2, 20,20,'20');
         INSERT INTO t2 VALUES(3, 3,3,'3');
 
-        SELECT a,b,c FROM t2 WHERE a=b AND c=b AND c=20;
+        SELECT a,b,c FROM t2 WHERE a=b AND c=CAST(b AS STRING) AND c='20';
     ]], {
         -- <transitive1-200>
         20, 20, "20"
@@ -73,7 +73,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "transitive1-210",
     [[
-        SELECT a,b,c FROM t2 WHERE a=b AND c=b AND c>='20' ORDER BY +a;
+        SELECT a,b,c FROM t2 WHERE a=b AND c=CAST(b AS STRING) AND c>='20' ORDER BY +a;
     ]], {
         -- <transitive1-210>
         3, 3, "3", 20, 20, "20"
@@ -83,7 +83,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "transitive1-220",
     [[
-        SELECT a,b,c FROM t2 WHERE a=b AND c=b AND c<='20' ORDER BY +a;
+        SELECT a,b,c FROM t2 WHERE a=b AND c=CAST(b AS STRING) AND c<='20' ORDER BY +a;
     ]], {
         -- <transitive1-220>
         20, 20, "20", 100, 100, "100"
@@ -338,7 +338,7 @@ test:do_execsql_test(
                    ON tvshow.idshow = episode.idshow
                  LEFT JOIN seasons
                         ON seasons.idshow = episode.idshow
-                           AND seasons.season = episode.c12
+                           AND seasons.season = CAST(episode.c12 AS INTEGER)
                  JOIN path
                    ON files.idpath = path.idpath
                  LEFT JOIN bookmark
@@ -378,7 +378,7 @@ test:do_execsql_test(
         FROM episodeview
             JOIN tvshowview ON tvshowview.idShow = episodeview.idShow
             JOIN seasons ON (seasons.idShow = tvshowview.idShow
-                             AND seasons.season = episodeview.c12)
+                             AND seasons.season = CAST(episodeview.c12 AS INTEGER))
             JOIN files ON files.idFile = episodeview.idFile
             JOIN tvshowlinkpath ON tvshowlinkpath.idShow = tvshowview.idShow
             JOIN path ON path.idPath = tvshowlinkpath.idPath
@@ -402,7 +402,7 @@ test:do_execsql_test(
     [[
         CREATE TABLE x(i INTEGER PRIMARY KEY, y TEXT);
         INSERT INTO x VALUES(10, '10');
-        SELECT * FROM x WHERE x.y>='1' AND x.y<'2' AND x.i=x.y;
+        SELECT * FROM x WHERE x.y>='1' AND x.y<'2' AND CAST(x.i AS STRING)=x.y;
     ]], {
         -- <transitive1-500>
         10, "10"
@@ -430,7 +430,7 @@ test:do_execsql_test(
     [[
         CREATE TABLE t3(i INTEGER PRIMARY KEY, t TEXT);
         INSERT INTO t3 VALUES(10, '10');
-        SELECT * FROM t3 WHERE i=t AND t = '10 ';
+        SELECT * FROM t3 WHERE CAST(i AS STRING)=t AND t = '10 ';
     ]], {
         -- <transitive1-520>
 
@@ -443,7 +443,7 @@ test:do_execsql_test(
         CREATE TABLE u1(x TEXT PRIMARY KEY, y INTEGER, z TEXT);
         CREATE INDEX i1 ON u1(x);
         INSERT INTO u1 VALUES('00013', 13, '013');
-        SELECT * FROM u1 WHERE x=y AND y=z AND z='013';
+        SELECT * FROM u1 WHERE CAST(x AS INTEGER)=y AND y=CAST(z AS INTEGER) AND z='013';
     ]], {
         -- <transitive1-530>
         "00013",13,"013"
diff --git a/test/sql-tap/where2.test.lua b/test/sql-tap/where2.test.lua
index f267be8..ca6b480 100755
--- a/test/sql-tap/where2.test.lua
+++ b/test/sql-tap/where2.test.lua
@@ -641,7 +641,7 @@ test:do_test(
     -- will attempt to convert to NUMERIC before the comparison.
     -- They will thus compare equal.
     --
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=b;
+    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE CAST(a AS INTEGER)=b;
   ]])
         end, {
             -- <where2-6.7>
@@ -655,7 +655,7 @@ test:do_test(
             return queryplan([[
     -- The + operator doesn't affect RHS.
     --
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=+b;
+    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE CAST(a AS INTEGER)=+b;
   ]])
         end, {
             -- <where2-6.9>
@@ -668,7 +668,7 @@ test:do_test(
         function()
             -- The same thing but with the expression flipped around.
             return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +b=a
+    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +b=CAST(a AS INTEGER)
   ]])
         end, {
             -- <where2-6.9.2>
@@ -680,7 +680,7 @@ test:do_test(
         "where2-6.10",
         function()
             return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +a=+b;
+    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +CAST(a AS INTEGER)=+b;
   ]])
         end, {
             -- <where2-6.10>
@@ -694,7 +694,7 @@ test:do_test(
             -- This will not attempt the OR optimization because of the a=b
             -- comparison.
             return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=b OR a='hello';
+    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE CAST(a AS INTEGER)=b OR a='hello';
   ]])
         end, {
             -- <where2-6.11>
@@ -707,7 +707,7 @@ test:do_test(
         function()
             -- Permutations of the expression terms.
             return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE b=a OR a='hello';
+    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE b=CAST(a AS INTEGER) OR a='hello';
   ]])
         end, {
             -- <where2-6.11.2>
@@ -720,7 +720,7 @@ test:do_test(
         function()
             -- Permutations of the expression terms.
             return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE 'hello'=a OR b=a;
+    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE 'hello'=a OR b=CAST(a AS INTEGER);
   ]])
         end, {
             -- <where2-6.11.3>
@@ -733,7 +733,7 @@ test:do_test(
         function()
             -- Permutations of the expression terms.
             return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR b=a;
+    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR b=CAST(a AS INTEGER);
   ]])
         end, {
             -- <where2-6.11.4>
@@ -750,7 +750,7 @@ test:do_test(
         "where2-6.12",
         function()
             return queryplan([[
-      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=+b OR a='hello';
+      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE CAST(a AS INTEGER)=+b OR a='hello';
     ]])
         end, {
             -- <where2-6.12>
@@ -762,7 +762,7 @@ test:do_test(
         "where2-6.12.2",
         function()
             return queryplan([[
-      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR +b=a;
+      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR +b=CAST(a AS INTEGER);
     ]])
         end, {
             -- <where2-6.12.2>
@@ -774,7 +774,7 @@ test:do_test(
         "where2-6.12.3",
         function()
             return queryplan([[
-      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +b=a OR a='hello';
+      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +b=CAST(a AS INTEGER) OR a='hello';
     ]])
         end, {
             -- <where2-6.12.3>
@@ -788,7 +788,7 @@ test:do_test(
             -- The addition of +a on the second term disabled the OR optimization.
             -- But we should still get the same empty-set result as in where2-6.9.
             return queryplan([[
-      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=+b OR +a='hello';
+      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE CAST(a AS INTEGER)=+b OR +a='hello';
     ]])
         end, {
             -- <where2-6.13>
diff --git a/test/sql-tap/where5.test.lua b/test/sql-tap/where5.test.lua
index 7492015..fc532c5 100755
--- a/test/sql-tap/where5.test.lua
+++ b/test/sql-tap/where5.test.lua
@@ -34,7 +34,7 @@ test:do_test("where5-1.0", function()
         INSERT INTO t3 SELECT * FROM t1;
     ]]
     return test:execsql [[
-        SELECT * FROM t1 WHERE x<0
+        SELECT * FROM t1 WHERE CAST(x AS INTEGER)<0
     ]]
 end, {
     -- <where5-1.0>
@@ -43,7 +43,7 @@ end, {
 })
 
 test:do_execsql_test("where5-1.1", [[
-    SELECT * FROM t1 WHERE x<=0
+    SELECT * FROM t1 WHERE CAST(x AS INTEGER)<=0
 ]], {
     -- <where5-1.1>
     '-1', '0'
@@ -51,7 +51,7 @@ test:do_execsql_test("where5-1.1", [[
 })
 
 test:do_execsql_test("where5-1.2", [[
-    SELECT * FROM t1 WHERE x=0
+    SELECT * FROM t1 WHERE CAST(x AS INTEGER)=0
 ]], {
     -- <where5-1.2>
     '0'
@@ -59,7 +59,7 @@ test:do_execsql_test("where5-1.2", [[
 })
 
 test:do_execsql_test("where5-1.3", [[
-    SELECT * FROM t1 WHERE x>=0
+    SELECT * FROM t1 WHERE CAST(x AS INTEGER)>=0
 ]], {
     -- <where5-1.3>
     '0', '1'
@@ -67,7 +67,7 @@ test:do_execsql_test("where5-1.3", [[
 })
 
 test:do_execsql_test("where5-1.4", [[
-    SELECT * FROM t1 WHERE x>0
+    SELECT * FROM t1 WHERE CAST(x AS INTEGER)>0
 ]], {
     -- <where5-1.4>
     '1'
@@ -75,7 +75,7 @@ test:do_execsql_test("where5-1.4", [[
 })
 
 test:do_execsql_test("where5-1.5", [[
-    SELECT * FROM t1 WHERE x<>0
+    SELECT * FROM t1 WHERE CAST(x AS INTEGER)<>0
 ]], {
     -- <where5-1.5>
     '-1', '1'
diff --git a/test/sql-tap/whereB.test.lua b/test/sql-tap/whereB.test.lua
index d98645f..eb11ba3 100755
--- a/test/sql-tap/whereB.test.lua
+++ b/test/sql-tap/whereB.test.lua
@@ -37,7 +37,7 @@ test:do_execsql_test(
         CREATE INDEX t2b ON t2(b);
         INSERT INTO t2 VALUES(2,'99');
 
-        SELECT x, a, y=b FROM t1, t2 ORDER BY +x, +a;
+        SELECT x, a, y=CAST(b AS INTEGER) FROM t1, t2 ORDER BY +x, +a;
     ]],
     {
     -- <whereB-1.1>
@@ -48,7 +48,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "whereB-1.2",
     [[
-        SELECT x, a, y=b FROM t1, t2 WHERE y=b;
+        SELECT x, a, y=CAST(b AS INTEGER) FROM t1, t2 WHERE y=CAST(b AS INTEGER);
     ]],
     {
     -- <whereB-1.2>
@@ -59,7 +59,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "whereB-1.3",
     [[
-        SELECT x, a, y=b FROM t1, t2 WHERE b=y;
+        SELECT x, a, y=CAST(b AS INTEGER) FROM t1, t2 WHERE CAST(b AS INTEGER)=y;
     ]],
     {
     -- <whereB-1.3>
@@ -70,7 +70,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "whereB-1.4",
     [[
-        SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
+        SELECT x, a, y=CAST(b AS INTEGER) FROM t1, t2 WHERE +y=+CAST(b AS INTEGER);
     ]],
     {
     -- <whereB-1.4>
@@ -82,7 +82,7 @@ test:do_execsql_test(
     "whereB-1.100",
     [[
         DROP INDEX t2b ON t2;
-        SELECT x, a, y=b FROM t1, t2 WHERE y=b;
+        SELECT x, a, y=CAST(b AS INTEGER) FROM t1, t2 WHERE y=CAST(b AS INTEGER);
     ]],
     {
     -- <whereB-1.100>
@@ -93,7 +93,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "whereB-1.101",
     [[
-        SELECT x, a, y=b FROM t1, t2 WHERE b=y;
+        SELECT x, a, y=CAST(b AS INTEGER) FROM t1, t2 WHERE CAST(b AS INTEGER)=y;
     ]],
     {
     -- <whereB-1.101>
@@ -104,7 +104,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "whereB-1.102",
     [[
-        SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
+        SELECT x, a, y=CAST(b AS INTEGER) FROM t1, t2 WHERE +y=+CAST(b AS INTEGER);
     ]],
     {
     -- <whereB-1.102>
@@ -329,29 +329,29 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-4.1>
-    1, 2, true
+    1, 2, false
     -- </whereB-4.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-4.2",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE y=b;
     ]],
     {
     -- <whereB-4.2>
-    1, 2, true
+    1, "Type mismatch: can not convert text to number"
     -- </whereB-4.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-4.3",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-4.3>
-    1, 2, true
+    1, "Type mismatch: can not convert text to number"
     -- </whereB-4.3>
     })
 
@@ -364,7 +364,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-4.4>
-    1, 2, true
     -- </whereB-4.4>
     })
 
@@ -376,7 +375,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-4.100>
-    1, 2, true
     -- </whereB-4.100>
     })
 
@@ -387,7 +385,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-4.101>
-    1, 2, true
     -- </whereB-4.101>
     })
 
@@ -400,7 +397,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-4.102>
-    1, 2, true
     -- </whereB-4.102>
     })
 
@@ -429,29 +425,29 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-5.1>
-    1, 2, true
+    1, 2, false
     -- </whereB-5.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-5.2",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE y=b;
     ]],
     {
     -- <whereB-5.2>
-    1, 2, true
+    1, "Type mismatch: can not convert text to integer"
     -- </whereB-5.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-5.3",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-5.3>
-    1, 2, true
+    1, "Type mismatch: can not convert text to integer"
     -- </whereB-5.3>
     })
 
@@ -464,7 +460,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-5.4>
-    1, 2, true
     -- </whereB-5.4>
     })
 
@@ -476,7 +471,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-5.100>
-    1, 2, true
     -- </whereB-5.100>
     })
 
@@ -487,7 +481,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-5.101>
-    1, 2, true
     -- </whereB-5.101>
     })
 
@@ -500,7 +493,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-5.102>
-    1, 2, true
     -- </whereB-5.102>
     })
 
@@ -529,29 +521,29 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-6.1>
-    1, 2, true
+    1, 2, false
     -- </whereB-6.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-6.2",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE y=b;
     ]],
     {
     -- <whereB-6.2>
-    1, 2, true
+    1, "Type mismatch: can not convert text to number"
     -- </whereB-6.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-6.3",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-6.3>
-    1, 2, true
+    1, "Type mismatch: can not convert text to number"
     -- </whereB-6.3>
     })
 
@@ -564,7 +556,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-6.4>
-    1, 2, true
     -- </whereB-6.4>
     })
 
@@ -576,7 +567,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-6.100>
-    1, 2, true
     -- </whereB-6.100>
     })
 
@@ -587,7 +577,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-6.101>
-    1, 2, true
     -- </whereB-6.101>
     })
 
@@ -600,7 +589,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-6.102>
-    1, 2, true
     -- </whereB-6.102>
     })
 
@@ -629,7 +617,7 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-7.1>
-    1, 2, true
+    1, 2, false
     -- </whereB-7.1>
     })
 
@@ -640,7 +628,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-7.2>
-    1, 2, true
     -- </whereB-7.2>
     })
 
@@ -651,7 +638,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-7.3>
-    1, 2, true
     -- </whereB-7.3>
     })
 
@@ -664,7 +650,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-7.4>
-    1, 2, true
     -- </whereB-7.4>
     })
 
@@ -676,7 +661,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-7.100>
-    1, 2, true
     -- </whereB-7.100>
     })
 
@@ -687,7 +671,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-7.101>
-    1, 2, true
     -- </whereB-7.101>
     })
 
@@ -700,7 +683,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-7.102>
-    1, 2, true
     -- </whereB-7.102>
     })
 
@@ -729,7 +711,7 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-8.1>
-    1, 2, true
+    1, 2, false
     -- </whereB-8.1>
     })
 
@@ -740,7 +722,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-8.2>
-    1, 2, true
     -- </whereB-8.2>
     })
 
@@ -751,7 +732,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-8.3>
-    1, 2, true
     -- </whereB-8.3>
     })
 
@@ -764,7 +744,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-8.4>
-    1, 2, true
     -- </whereB-8.4>
     })
 
@@ -776,7 +755,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-8.100>
-    1, 2, true
     -- </whereB-8.100>
     })
 
@@ -787,7 +765,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-8.101>
-    1, 2, true
     -- </whereB-8.101>
     })
 
@@ -800,7 +777,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-8.102>
-    1, 2, true
     -- </whereB-8.102>
     })
 
@@ -829,7 +805,7 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-9.1>
-    1, 2, true
+    1, 2, false
     -- </whereB-9.1>
     })
 
@@ -840,7 +816,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-9.2>
-    1, 2, true
     -- </whereB-9.2>
     })
 
@@ -851,7 +826,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-9.3>
-    1, 2, true
     -- </whereB-9.3>
     })
 
@@ -864,7 +838,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-9.4>
-    1, 2, true
     -- </whereB-9.4>
     })
 
@@ -876,7 +849,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-9.100>
-    1, 2, true
     -- </whereB-9.100>
     })
 
@@ -887,7 +859,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-9.101>
-    1, 2, true
     -- </whereB-9.101>
     })
 
@@ -900,7 +871,6 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-9.102>
-    1, 2, true
     -- </whereB-9.102>
     })
 
diff --git a/test/sql-tap/whereC.test.lua b/test/sql-tap/whereC.test.lua
index 89459de..2f214ef 100755
--- a/test/sql-tap/whereC.test.lua
+++ b/test/sql-tap/whereC.test.lua
@@ -1,7 +1,7 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
 local yaml = require('yaml')
-test:plan(41)
+test:plan(29)
 
 --!./tcltestrunner.lua
 -- 2011 November 16
@@ -54,10 +54,6 @@ test:do_execsql_test(
 --local function main()
 test:test("main", function()
     local data = {{"SELECT i FROM t1 WHERE a=1 AND b=2 AND i>3",         {4, 5}},
-                  -- {"SELECT i FROM t1 WHERE rowid='12'",                  {12}},
-                  {"SELECT i FROM t1 WHERE a=1 AND b='2'",               {3, 4, 5}},
-                  {"SELECT i FROM t1 WHERE a=1 AND b='2' AND i>'3'",     {4, 5}},
-                  {"SELECT i FROM t1 WHERE a=1 AND b='2' AND i<5",       {3, 4}},
                   {"SELECT i FROM t1 WHERE a=2 AND b=2 AND i<12",        {10, 11}},
                   {"SELECT i FROM t1 WHERE a IN(1, 2) AND b=2 AND i<11", {3, 4, 5, 10}},
                   {"SELECT i FROM t1 WHERE a=2 AND b=2 AND i BETWEEN 10 AND 12", {10, 11, 12}},
@@ -65,9 +61,7 @@ test:test("main", function()
                   {"SELECT i FROM t1 WHERE a=2 AND b=2 AND i BETWEEN 10 AND 11", {10, 11}},
                   {"SELECT i FROM t1 WHERE a=2 AND b=2 AND i BETWEEN 12 AND 10", {}},
                   {"SELECT i FROM t1 WHERE a=2 AND b=2 AND i<NULL",      {}},
-                  {"SELECT i FROM t1 WHERE a=2 AND b=2 AND i>=NULL",     {}},
-                  {"SELECT i FROM t1 WHERE a=1 AND b='2' AND i<4.5",     {3, 4}}}
-                  -- {"SELECT i FROM t1 WHERE rowid IS '12'",               {12}}}
+                  {"SELECT i FROM t1 WHERE a=2 AND b=2 AND i>=NULL",     {}}}
 
     for tn, t in ipairs(data) do
         test:do_execsql_test(
diff --git a/test/sql/boolean.result b/test/sql/boolean.result
index 112e41a..483873b 100644
--- a/test/sql/boolean.result
+++ b/test/sql/boolean.result
@@ -137,13 +137,19 @@ INSERT INTO ts(s) VALUES ('abc'), (12.5);
  | ...
 SELECT s FROM ts WHERE s = true;
  | ---
- | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - metadata:
+ |   - name: S
+ |     type: scalar
+ |   rows:
+ |   - [true]
  | ...
 SELECT s FROM ts WHERE s < true;
  | ---
- | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - metadata:
+ |   - name: S
+ |     type: scalar
+ |   rows:
+ |   - [false]
  | ...
 SELECT s FROM ts WHERE s IN (true, 1, 'abcd');
  | ---
@@ -3389,22 +3395,22 @@ SELECT false < 2;
 SELECT 2 > true;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT 2 > false;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT 2 < true;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT 2 < false;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 
 SELECT a1, a1 > 2 FROM t6
@@ -3420,12 +3426,12 @@ SELECT a1, a1 < 2 FROM t6
 SELECT a1, 2 > a1 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a1, 2 < a1 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a2, a2 > 2 FROM t6
  | ---
@@ -3440,12 +3446,12 @@ SELECT a2, a2 < 2 FROM t6
 SELECT a2, 2 > a2 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a2, 2 < a2 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 
 SELECT b, true > b FROM t7;
@@ -3471,22 +3477,22 @@ SELECT b, false < b FROM t7;
 SELECT b, b > true FROM t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT b, b > false FROM t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT b, b < true FROM t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT b, b < false FROM t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 
 SELECT a1, b, a1 > b FROM t6, t7;
@@ -3502,12 +3508,12 @@ SELECT a1, b, a1 < b FROM t6, t7;
 SELECT a1, b, b > a1 FROM t6, t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a1, b, b < a1 FROM t6, t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a2, b, a2 > b FROM t6, t7;
  | ---
@@ -3522,12 +3528,12 @@ SELECT a2, b, a2 < b FROM t6, t7;
 SELECT a2, b, b > a2 FROM t6, t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a2, b, b < a2 FROM t6, t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 
 SELECT true >= 2;
@@ -3553,22 +3559,22 @@ SELECT false <= 2;
 SELECT 2 >= true;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT 2 >= false;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT 2 <= true;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT 2 <= false;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 
 SELECT a1, a1 >= 2 FROM t6
@@ -3584,12 +3590,12 @@ SELECT a1, a1 <= 2 FROM t6
 SELECT a1, 2 >= a1 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a1, 2 <= a1 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a2, a2 >= 2 FROM t6
  | ---
@@ -3604,12 +3610,12 @@ SELECT a2, a2 <= 2 FROM t6
 SELECT a2, 2 >= a2 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a2, 2 <= a2 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 
 SELECT b, true >= b FROM t7;
@@ -3635,22 +3641,22 @@ SELECT b, false <= b FROM t7;
 SELECT b, b >= true FROM t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT b, b >= false FROM t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT b, b <= true FROM t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT b, b <= false FROM t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 
 SELECT a1, b, a1 >= b FROM t6, t7;
@@ -3666,12 +3672,12 @@ SELECT a1, b, a1 <= b FROM t6, t7;
 SELECT a1, b, b >= a1 FROM t6, t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a1, b, b <= a1 FROM t6, t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a2, b, a2 >= b FROM t6, t7;
  | ---
@@ -3686,12 +3692,12 @@ SELECT a2, b, a2 <= b FROM t6, t7;
 SELECT a2, b, b >= a2 FROM t6, t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a2, b, b <= a2 FROM t6, t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 
 SELECT true == 2;
@@ -3717,22 +3723,22 @@ SELECT false != 2;
 SELECT 2 == true;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT 2 == false;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT 2 != true;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT 2 != false;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 
 SELECT a1, a1 == 2 FROM t6
@@ -3748,12 +3754,12 @@ SELECT a1, a1 != 2 FROM t6
 SELECT a1, 2 == a1 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a1, 2 != a1 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a2, a2 == 2 FROM t6
  | ---
@@ -3768,12 +3774,12 @@ SELECT a2, a2 != 2 FROM t6
 SELECT a2, 2 == a2 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a2, 2 != a2 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 
 SELECT b, true == b FROM t7;
@@ -3799,22 +3805,22 @@ SELECT b, false != b FROM t7;
 SELECT b, b == true FROM t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT b, b == false FROM t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT b, b != true FROM t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT b, b != false FROM t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 
 SELECT a1, b, a1 == b FROM t6, t7;
@@ -3830,12 +3836,12 @@ SELECT a1, b, a1 != b FROM t6, t7;
 SELECT a1, b, b == a1 FROM t6, t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a1, b, b != a1 FROM t6, t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a2, b, a2 == b FROM t6, t7;
  | ---
@@ -3850,12 +3856,12 @@ SELECT a2, b, a2 != b FROM t6, t7;
 SELECT a2, b, b == a2 FROM t6, t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a2, b, b != a2 FROM t6, t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 
 SELECT true IN (0, 1, 2, 3);
@@ -4534,22 +4540,22 @@ SELECT false < 2.3;
 SELECT 2.3 > true;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT 2.3 > false;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT 2.3 < true;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT 2.3 < false;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 
 SELECT a1, a1 > 2.3 FROM t6
@@ -4565,12 +4571,12 @@ SELECT a1, a1 < 2.3 FROM t6
 SELECT a1, 2.3 > a1 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a1, 2.3 < a1 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a2, a2 > 2.3 FROM t6
  | ---
@@ -4585,12 +4591,12 @@ SELECT a2, a2 < 2.3 FROM t6
 SELECT a2, 2.3 > a2 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a2, 2.3 < a2 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 
 SELECT c, true > c FROM t8;
@@ -4616,22 +4622,22 @@ SELECT c, false < c FROM t8;
 SELECT c, c > true FROM t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT c, c > false FROM t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT c, c < true FROM t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT c, c < false FROM t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 
 SELECT a1, c, a1 > c FROM t6, t8;
@@ -4647,12 +4653,12 @@ SELECT a1, c, a1 < c FROM t6, t8;
 SELECT a1, c, c > a1 FROM t6, t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a1, c, c < a1 FROM t6, t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a2, c, a2 > c FROM t6, t8;
  | ---
@@ -4667,12 +4673,12 @@ SELECT a2, c, a2 < c FROM t6, t8;
 SELECT a2, c, c > a2 FROM t6, t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a2, c, c < a2 FROM t6, t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 
 SELECT true >= 2.3;
@@ -4698,22 +4704,22 @@ SELECT false <= 2.3;
 SELECT 2.3 >= true;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT 2.3 >= false;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT 2.3 <= true;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT 2.3 <= false;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 
 SELECT a1, a1 >= 2.3 FROM t6
@@ -4729,12 +4735,12 @@ SELECT a1, a1 <= 2.3 FROM t6
 SELECT a1, 2.3 >= a1 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a1, 2.3 <= a1 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a2, a2 >= 2.3 FROM t6
  | ---
@@ -4749,12 +4755,12 @@ SELECT a2, a2 <= 2.3 FROM t6
 SELECT a2, 2.3 >= a2 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a2, 2.3 <= a2 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 
 SELECT c, true >= c FROM t8;
@@ -4780,22 +4786,22 @@ SELECT c, false <= c FROM t8;
 SELECT c, c >= true FROM t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT c, c >= false FROM t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT c, c <= true FROM t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT c, c <= false FROM t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 
 SELECT a1, c, a1 >= c FROM t6, t8;
@@ -4811,12 +4817,12 @@ SELECT a1, c, a1 <= c FROM t6, t8;
 SELECT a1, c, c >= a1 FROM t6, t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a1, c, c <= a1 FROM t6, t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a2, c, a2 >= c FROM t6, t8;
  | ---
@@ -4831,12 +4837,12 @@ SELECT a2, c, a2 <= c FROM t6, t8;
 SELECT a2, c, c >= a2 FROM t6, t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a2, c, c <= a2 FROM t6, t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 
 SELECT true == 2.3;
@@ -4862,22 +4868,22 @@ SELECT false != 2.3;
 SELECT 2.3 == true;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT 2.3 == false;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT 2.3 != true;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT 2.3 != false;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 
 SELECT a1, a1 == 2.3 FROM t6
@@ -4893,12 +4899,12 @@ SELECT a1, a1 != 2.3 FROM t6
 SELECT a1, 2.3 == a1 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a1, 2.3 != a1 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a2, a2 == 2.3 FROM t6
  | ---
@@ -4913,12 +4919,12 @@ SELECT a2, a2 != 2.3 FROM t6
 SELECT a2, 2.3 == a2 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a2, 2.3 != a2 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 
 SELECT c, true == c FROM t8;
@@ -4944,22 +4950,22 @@ SELECT c, false != c FROM t8;
 SELECT c, c == true FROM t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT c, c == false FROM t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT c, c != true FROM t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT c, c != false FROM t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 
 SELECT a1, c, a1 == c FROM t6, t8;
@@ -4975,12 +4981,12 @@ SELECT a1, c, a1 != c FROM t6, t8;
 SELECT a1, c, c == a1 FROM t6, t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a1, c, c != a1 FROM t6, t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a2, c, a2 == c FROM t6, t8;
  | ---
@@ -4995,12 +5001,12 @@ SELECT a2, c, a2 != c FROM t6, t8;
 SELECT a2, c, c == a2 FROM t6, t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a2, c, c != a2 FROM t6, t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 
 SELECT true IN (0.1, 1.2, 2.3, 3.4);
@@ -5290,22 +5296,22 @@ SELECT false < 'abc';
 SELECT 'abc' > true;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 SELECT 'abc' > false;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 SELECT 'abc' < true;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 SELECT 'abc' < false;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 
 SELECT d, true > d FROM t9;
@@ -5331,22 +5337,22 @@ SELECT d, false < d FROM t9;
 SELECT d, d > true FROM t9;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 SELECT d, d > false FROM t9;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 SELECT d, d < true FROM t9;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 SELECT d, d < false FROM t9;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 
 SELECT a1, d, a1 > d FROM t6, t9;
@@ -5362,12 +5368,12 @@ SELECT a1, d, a1 < d FROM t6, t9;
 SELECT a1, d, d > a1 FROM t6, t9;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 SELECT a1, d, d < a1 FROM t6, t9;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 SELECT a2, d, a2 > d FROM t6, t9;
  | ---
@@ -5382,12 +5388,12 @@ SELECT a2, d, a2 < d FROM t6, t9;
 SELECT a2, d, d > a2 FROM t6, t9;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 SELECT a2, d, d < a2 FROM t6, t9;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 
 SELECT true || 'abc';
diff --git a/test/sql/types.result b/test/sql/types.result
index 38e4385..97b57a8 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -352,7 +352,7 @@ box.execute("SELECT * FROM tboolean WHERE s1 = x'44';")
 box.execute("SELECT * FROM tboolean WHERE s1 = 'abc';")
 ---
 - null
-- 'Type mismatch: can not convert abc to boolean'
+- 'Type mismatch: can not convert text to boolean'
 ...
 box.execute("SELECT * FROM tboolean WHERE s1 = 1;")
 ---
@@ -614,10 +614,11 @@ box.execute("SELECT 18446744073709551615.0 > 18446744073709551615")
   rows:
   - [true]
 ...
-box.execute("SELECT 18446744073709551615 IN ('18446744073709551615', 18446744073709551615.0)")
+box.execute("SELECT 18446744073709551615 IN ('18446744073709551615', 18446744073709551615.0, 1)")
 ---
 - metadata:
-  - name: 18446744073709551615 IN ('18446744073709551615', 18446744073709551615.0)
+  - name: 18446744073709551615 IN ('18446744073709551615', 18446744073709551615.0,
+      1)
     type: boolean
   rows:
   - [true]
diff --git a/test/sql/types.test.lua b/test/sql/types.test.lua
index bd14b34..f9e2531 100644
--- a/test/sql/types.test.lua
+++ b/test/sql/types.test.lua
@@ -151,7 +151,7 @@ box.execute("SELECT 18446744073709551610 - 18446744073709551615;")
 box.execute("SELECT 18446744073709551615 = null;")
 box.execute("SELECT 18446744073709551615 = 18446744073709551615.0;")
 box.execute("SELECT 18446744073709551615.0 > 18446744073709551615")
-box.execute("SELECT 18446744073709551615 IN ('18446744073709551615', 18446744073709551615.0)")
+box.execute("SELECT 18446744073709551615 IN ('18446744073709551615', 18446744073709551615.0, 1)")
 box.execute("SELECT 1 LIMIT 18446744073709551615;")
 box.execute("SELECT 1 LIMIT 1 OFFSET 18446744073709551614;")
 box.execute("SELECT CAST('18446744073' || '709551616' AS INTEGER);")
-- 
2.7.4

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Tarantool-patches] [PATCH v1 1/1] sql: remove implicit cast for COMPARISON
  2020-03-20 12:34 [Tarantool-patches] [PATCH v1 1/1] sql: remove implicit cast for COMPARISON imeevma
@ 2020-03-29 22:29 ` Vladislav Shpilevoy
  2020-03-30 11:38   ` Nikita Pettik
  2020-04-21 12:42   ` Mergen Imeev
  0 siblings, 2 replies; 8+ messages in thread
From: Vladislav Shpilevoy @ 2020-03-29 22:29 UTC (permalink / raw)
  To: imeevma, tsafin, tarantool-patches

Hi! Thanks for the patch!

See 15 comments below.

I don't think I understood all the changed (because I am very out of
context), so I will revisited many of them when you send v2.

On 20/03/2020 13:34, imeevma@tarantool.org wrote:
> This patch removes implicit cast for comparison. Also, it make
> search using an index work the same way as in case of fullscan in
> most cases.
> 
> Closes #4230
> Closes #4783
> ---
> https://github.com/tarantool/tarantool/issues/4230
> https://github.com/tarantool/tarantool/issues/4783
> https://github.com/tarantool/tarantool/tree/imeevma/gh-4230-remove-implicit-cast-for-index-search-second
> 
> @ChangeLog Remove implicit cast for comparison gh-4230

1. Worth adding more details. What implicit cast? All of them?

Do we need a docbot request for this?

> diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
> index 1579cc9..cd626bd 100644
> --- a/src/box/sql/sqlInt.h
> +++ b/src/box/sql/sqlInt.h
> @@ -1304,6 +1304,9 @@ enum trim_side_mask {
>  				 (X) == FIELD_TYPE_UNSIGNED || \
>  				 (X) == FIELD_TYPE_DOUBLE)
>  
> +#define sql_mp_type_is_numeric(X)  ((X) == MP_INT || (X) == MP_UINT || \
> +				    (X) == MP_FLOAT || (X) == MP_DOUBLE)

2. Better make it static inline function.

> diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
> index e8a029a..8c95fd4 100644
> --- a/src/box/sql/vdbe.c
> +++ b/src/box/sql/vdbe.c
> @@ -660,6 +660,216 @@ vdbe_field_ref_fetch_field(struct vdbe_field_ref *field_ref, uint32_t fieldno)
>  }
>  
>  /**
> + * Prepare mem to use for comparison with value with type UNSIGNED
> + * from index.
> + *
> + * @param[out] mem Mem to prepare for comparison.
> + * @param[in][out] op Operation that was before preperation and
> + *                 operation after.

3. preperation -> preparation. The same in the next functions.

> + * @param is_eq True if operation was EQ.
> + * @param[out] is_none True if nothing will be found.
> + * @retval 0 on success.
> + * @retval -1 on error.
> + */
> +static int
> +sql_mem_to_unsigned_for_comp(struct Mem *mem, uint32_t *op, int is_eq,

4. Opcode has type u8 in UnpackedRecord. Better make it the
same here. The same in other places.

5. is_eq is a flag, and therefore should be a boolean. The
same in the next functions.

> +			     bool *is_none)
> +{
> +	assert(*is_none == false);> +	uint32_t orig_op = *op;
> +	enum mp_type mp_type = sql_value_type(mem);
> +	assert(mp_type == MP_DOUBLE || mp_type == MP_INT);
> +	if (mp_type == MP_INT || mem->u.r < 0) {
> +		if (orig_op == OP_SeekGE || orig_op == OP_SeekGT) {
> +			mem_set_u64(mem, 0);
> +			*op = OP_SeekGE;
> +			return 0;
> +		}
> +		*is_none = true;
> +		return 0;
> +	}
> +	double d = mem->u.r;
> +	if (d >= UINT64_MAX) {
> +		if (orig_op == OP_SeekLE || orig_op == OP_SeekLT) {
> +			mem_set_u64(mem, UINT64_MAX);
> +			*op = OP_SeekLE;
> +			return 0;
> +		}
> +		*is_none = true;
> +		return 0;
> +	}
> +	uint64_t u = (uint64_t)d;
> +	if (d != u && is_eq) {
> +		*is_none = true;
> +		return 0;
> +	}
> +	mem_set_u64(mem, u);
> +	if (d == u)
> +		return 0;
> +	if (orig_op == OP_SeekGE)
> +		*op = OP_SeekGT;
> +	else if (orig_op == OP_SeekLT)
> +		*op = OP_SeekLE;
> +	return 0;
> +}
> +
> +/**
> + * Prepare mem to use for comparison with value with type INTEGER
> + * from index.
> + *
> + * @param[out] mem Mem to prepare for comparison.
> + * @param[in][out] op Operation that was before preperation and
> + *                 operation after.
> + * @param is_eq True if operation was EQ.
> + * @param[out] is_none True if nothing will be found.
> + * @retval 0 on success.
> + * @retval -1 on error.
> + */
> +static int
> +sql_mem_to_integer_for_comp(struct Mem *mem, uint32_t *op, int is_eq,
> +			    bool *is_none)
> +{
> +	assert(*is_none == false);
> +	uint32_t orig_op = *op;
> +	assert(sql_value_type(mem) == MP_DOUBLE);
> +	double d = mem->u.r;
> +	if (d < INT64_MIN) {
> +		if (orig_op == OP_SeekGE || orig_op == OP_SeekGT) {
> +			mem_set_i64(mem, INT64_MIN);
> +			*op = OP_SeekGE;
> +			return 0;
> +		}
> +		*is_none = true;
> +		return 0;
> +	}
> +	if (d >= UINT64_MAX) {
> +		if (orig_op == OP_SeekLE || orig_op == OP_SeekLT) {
> +			mem_set_u64(mem, UINT64_MAX);
> +			*op = OP_SeekLE;
> +			return 0;
> +		}
> +		*is_none = true;
> +		return 0;
> +	}
> +	int64_t i = (int64_t)d;
> +	uint64_t u = (uint64_t)d;
> +	if (d != i && d != u && is_eq) {
> +		*is_none = true;
> +		return 0;
> +	}
> +	if (d > 0)

6. >= 0?

> +		mem_set_u64(mem, u);
> +	else
> +		mem_set_i64(mem, i);
> +	if (d == u || d == i)
> +		return 0;
> +	if (d >= 0) {
> +		if (orig_op == OP_SeekGE)
> +			*op = OP_SeekGT;
> +		else if (orig_op == OP_SeekLT)
> +			*op = OP_SeekLE;
> +		return 0;
> +	}
> +	if (orig_op == OP_SeekLE)
> +		*op = OP_SeekLT;
> +	else if (orig_op == OP_SeekGT)
> +		*op = OP_SeekGE;
> +	return 0;
> +}
> +
> +/**
> + * Prepare mem to use for comparison with value with type DOUBLE
> + * from index.
> + *
> + * @param[out] mem Mem to prepare for comparison.
> + * @param[in][out] op Operation that was before preperation and
> + *                 operation after.
> + * @param is_eq True if operation was EQ.
> + * @param[out] is_none True if nothing will be found.
> + * @retval 0 on success.
> + * @retval -1 on error.
> + */
> +static int
> +sql_mem_to_double_for_comp(struct Mem *mem, uint32_t *op, int is_eq,
> +			   bool *is_none)
> +{
> +	assert(*is_none == false);
> +	uint32_t orig_op = *op;
> +	enum mp_type mp_type = sql_value_type(mem);

7. Is there a ticket to stop conveting MEM_* to MP_*? MP_* now
contains all MEM_* and even more, right?

> +	assert(mp_type == MP_INT || mp_type == MP_UINT);
> +	int64_t i = mem->u.i;
> +	uint64_t u = mem->u.u;
> +	/* 2^53 == 9007199254740992 */
> +	if (mp_type == MP_INT && i > -9007199254740992) {

8. Is it possible to replace this with 'i == (int64)(double)i' ?
The same below. Because these double vs int are always tricky.
And I would like to avoid any constant assumptions here. For
example, you excluded 2^53, but 2^53 can be stored (from what I
saw and tested). So it would be more correct to write >= -9007199254740992,
not >. However the 2-cast solution may work too, and does not
use constants.

> +		sqlVdbeMemSetDouble(mem, i);
> +		return 0;
> +	} else if (mp_type == MP_UINT && u < 9007199254740992) {
> +		sqlVdbeMemSetDouble(mem, u);
> +		return 0;
> +	}
> +
> +	double d = mp_type == MP_INT ? (double)i : (double)u;
> +	if (is_eq) {
> +		if (i != d && u != d)
> +			*is_none = true;
> +		else
> +			sqlVdbeMemSetDouble(mem, d);
> +		return 0;
> +	}
> +
> +	sqlVdbeMemSetDouble(mem, d);
> +	if (mp_type == MP_INT) {
> +		if (orig_op == OP_SeekGT && d > i)
> +			*op = OP_SeekGE;
> +		else if (orig_op == OP_SeekGE && d < i)
> +			*op = OP_SeekGT;
> +		else if (orig_op == OP_SeekLT && d < i)
> +			*op = OP_SeekLE;
> +		else if (orig_op == OP_SeekLE && d > i)
> +			*op = OP_SeekLT;
> +		return 0;
> +	}
> +	if (orig_op == OP_SeekGT && d > u)
> +		*op = OP_SeekGE;
> +	else if (orig_op == OP_SeekGE && d < u)
> +		*op = OP_SeekGT;
> +	else if (orig_op == OP_SeekLT && d < u)
> +		*op = OP_SeekLE;
> +	else if (orig_op == OP_SeekLE && d > u)
> +		*op = OP_SeekLT;
> +	return 0;
> +}
> +
> +/**
> + * Prepare mem to use for comparison with value with numeric type

9. No mem among the arguments.

> + * from index.
> + *
> + * @param[in][out] r Unpacked tuple that should be prepared for
> + *                 comparison.
> + * @param i field of unpacked tuple that should be prepared.
> + * @param is_eq True if operation was EQ.
> + * @param[out] is_none True if nothing will be found.
> + * @retval 0 on success.
> + * @retval -1 on error.
> + */
> +static int
> +sql_prepare_rec_for_comp(struct UnpackedRecord *r, int i, int is_eq,
> +			 bool *is_none)
> +{
> +	struct Mem *mem = &r->aMem[i];
> +	enum field_type field_type = r->key_def->parts[i].type;
> +	uint32_t opcode = r->opcode;
> +	if (field_type == FIELD_TYPE_UNSIGNED)
> +		sql_mem_to_unsigned_for_comp(mem, &opcode, is_eq, is_none);
> +	else if (field_type == FIELD_TYPE_INTEGER)
> +		sql_mem_to_integer_for_comp(mem, &opcode, is_eq, is_none);
> +	else
> +		sql_mem_to_double_for_comp(mem, &opcode, is_eq, is_none);
> +	r->opcode = opcode;
> +	return 0;
> +}
> @@ -2133,189 +2336,109 @@ case OP_Lt:               /* same as TK_LT, jump, in1, in3 */
>  case OP_Le:               /* same as TK_LE, jump, in1, in3 */
>  case OP_Gt:               /* same as TK_GT, jump, in1, in3 */
>  case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
> -	int res, res2;      /* Result of the comparison of pIn1 against pIn3 */
> -	u32 flags1;         /* Copy of initial value of pIn1->flags */
> -	u32 flags3;         /* Copy of initial value of pIn3->flags */
> -
> +	/*
> +	 * Result of comparison: more than 0 if l > r,
> +	 * 0 if l == r, less than 0 if l < r.
> +	 */
> +	int cmp_res;
> +	/* Result of the operation. */
> +	bool result;
>  	pIn1 = &aMem[pOp->p1];
>  	pIn3 = &aMem[pOp->p3];
> -	flags1 = pIn1->flags;
> -	flags3 = pIn3->flags;
> -	enum field_type ft_p1 = pIn1->field_type;
> -	enum field_type ft_p3 = pIn3->field_type;
> -	if ((flags1 | flags3)&MEM_Null) {
> -		/* One or both operands are NULL */
> -		if (pOp->p5 & SQL_NULLEQ) {
> -			/* If SQL_NULLEQ is set (which will only happen if the operator is
> -			 * OP_Eq or OP_Ne) then take the jump or not depending on whether
> -			 * or not both operands are null.
> -			 */
> -			assert(pOp->opcode==OP_Eq || pOp->opcode==OP_Ne);
> -			assert((flags1 & MEM_Cleared)==0);
> -			assert((pOp->p5 & SQL_JUMPIFNULL)==0);
> -			if ((flags1&flags3&MEM_Null)!=0
> -			    && (flags3&MEM_Cleared)==0
> -				) {
> -				res = 0;  /* Operands are equal */
> -			} else {
> -				res = 1;  /* Operands are not equal */
> -			}
> -		} else {
> -			/* SQL_NULLEQ is clear and at least one operand is NULL,
> -			 * then the result is always NULL.
> -			 * The jump is taken if the SQL_JUMPIFNULL bit is set.
> +
> +	bool has_scalar = (pIn1->field_type == FIELD_TYPE_SCALAR) ||
> +			  (pIn3->field_type == FIELD_TYPE_SCALAR);
> +	enum mp_type ltype = sql_value_type(pIn1);
> +	enum mp_type rtype = sql_value_type(pIn3);
> +	assert(ltype != MP_MAP && rtype != MP_MAP);
> +	assert(ltype != MP_ARRAY && rtype != MP_ARRAY);
> +	int mp_classes_comp = mp_type_classes_comp(rtype, ltype);
> +
> +	if (ltype == MP_NIL || rtype == MP_NIL) {
> +		if ((pOp->p5 & SQL_NULLEQ) == 0) {
> +			/*
> +			 * SQL_NULLEQ is clear and at least one
> +			 * operand is NULL, then the result is
> +			 * always NULL. The jump is taken if the
> +			 * SQL_JUMPIFNULL bit is set.
>  			 */
>  			if (pOp->p5 & SQL_STOREP2) {
>  				pOut = vdbe_prepare_null_out(p, pOp->p2);
> -				iCompare = 1;    /* Operands are not equal */
> +				iCompare = 1;
>  				REGISTER_TRACE(p, pOp->p2, pOut);
>  			} else {
>  				VdbeBranchTaken(2,3);
> -				if (pOp->p5 & SQL_JUMPIFNULL) {
> +				if (pOp->p5 & SQL_JUMPIFNULL)
>  					goto jump_to_p2;
> -				}

10. I know these places violated our style, but lets keep
them. Since they are not stictly related to the patch. We will
have a chance to fix them later.

>  			}
>  			break;
>  		}
> -	} else if (((flags1 | flags3) & MEM_Bool) != 0 ||
> -		   ((flags1 | flags3) & MEM_Blob) != 0) {
>  		/*
> -		 * If one of values is of type BOOLEAN or VARBINARY,
> -		 * then the second one must be of the same type as
> -		 * well. Otherwise an error is raised.
> +		 * If SQL_NULLEQ is set (which will only happen if
> +		 * the operator is OP_Eq or OP_Ne) then take the
> +		 * jump or not depending on whether or not both
> +		 * operands are null.
>  		 */
> -		int type_arg1 = flags1 & (MEM_Bool | MEM_Blob);
> -		int type_arg3 = flags3 & (MEM_Bool | MEM_Blob);
> -		if (type_arg1 != type_arg3) {
> -			char *inconsistent_type = type_arg1 != 0 ?
> -						  mem_type_to_str(pIn3) :
> -						  mem_type_to_str(pIn1);
> -			char *expected_type     = type_arg1 != 0 ?
> -						  mem_type_to_str(pIn1) :
> -						  mem_type_to_str(pIn3);
> -			diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
> -				 inconsistent_type, expected_type);
> -			goto abort_due_to_error;
> -		}
> -		res = sqlMemCompare(pIn3, pIn1, NULL);
> +		assert(pOp->opcode == OP_Eq || pOp->opcode == OP_Ne);
> +		assert((pOp->p5 & SQL_JUMPIFNULL) == 0);
> +		cmp_res = !(ltype == MP_NIL && rtype == MP_NIL);

11. The compiler is likely to help us here, but still lets apply '!'.
It will look

    ltype != MP_NIL || rtype != MP_NIL

> +	} else if (mp_classes_comp == 0) {
> +		cmp_res = sqlMemCompare(pIn3, pIn1, pOp->p4.pColl);
> +	} else if (has_scalar) {
> +		cmp_res = mp_classes_comp;
>  	} else {
> -		enum field_type type = pOp->p5 & FIELD_TYPE_MASK;
> -		if (sql_type_is_numeric(type)) {
> -			if ((flags1 | flags3)&MEM_Str) {
> -				if ((flags1 & MEM_Str) == MEM_Str) {
> -					mem_apply_numeric_type(pIn1);
> -					testcase( flags3!=pIn3->flags); /* Possible if pIn1==pIn3 */
> -					flags3 = pIn3->flags;
> -				}
> -				if ((flags3 & MEM_Str) == MEM_Str) {
> -					if (mem_apply_numeric_type(pIn3) != 0) {
> -						diag_set(ClientError,
> -							 ER_SQL_TYPE_MISMATCH,
> -							 sql_value_to_diag_str(pIn3),
> -							 "numeric");
> -						goto abort_due_to_error;
> -					}
> +		diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
> +			 mem_type_to_str(pIn1), mem_type_to_str(pIn3));
> +		goto abort_due_to_error;
> +	}
>  
> -				}
> -			}
> -			/* Handle the common case of integer comparison here, as an
> -			 * optimization, to avoid a call to sqlMemCompare()
> -			 */
> -			if ((pIn1->flags & pIn3->flags & (MEM_Int | MEM_UInt)) != 0) {
> -				if ((pIn1->flags & pIn3->flags & MEM_Int) != 0) {
> -					if (pIn3->u.i > pIn1->u.i)
> -						res = +1;
> -					else if (pIn3->u.i < pIn1->u.i)
> -						res = -1;
> -					else
> -						res = 0;
> -					goto compare_op;
> -				}
> -				if ((pIn1->flags & pIn3->flags & MEM_UInt) != 0) {
> -					if (pIn3->u.u > pIn1->u.u)
> -						res = +1;
> -					else if (pIn3->u.u < pIn1->u.u)
> -						res = -1;
> -					else
> -						res = 0;
> -					goto compare_op;
> -				}
> -				if ((pIn1->flags & MEM_UInt) != 0 &&
> -				    (pIn3->flags & MEM_Int) != 0) {
> -					res = -1;
> -					goto compare_op;
> -				}
> -				res = 1;
> -				goto compare_op;
> -			}
> -		} else if (type == FIELD_TYPE_STRING) {
> -			if ((flags1 & MEM_Str) == 0 &&
> -			    (flags1 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
> -				testcase( pIn1->flags & MEM_Int);
> -				testcase( pIn1->flags & MEM_Real);
> -				sqlVdbeMemStringify(pIn1);
> -				testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn));
> -				flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
> -				assert(pIn1!=pIn3);
> -			}
> -			if ((flags3 & MEM_Str) == 0 &&
> -			    (flags3 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
> -				testcase( pIn3->flags & MEM_Int);
> -				testcase( pIn3->flags & MEM_Real);
> -				sqlVdbeMemStringify(pIn3);
> -				testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn));
> -				flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & MEM_TypeMask);
> -			}
> -		}
> -		assert(pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0);
> -		res = sqlMemCompare(pIn3, pIn1, pOp->p4.pColl);
> -	}
> -			compare_op:
> -	switch( pOp->opcode) {
> -	case OP_Eq:    res2 = res==0;     break;
> -	case OP_Ne:    res2 = res;        break;
> -	case OP_Lt:    res2 = res<0;      break;
> -	case OP_Le:    res2 = res<=0;     break;
> -	case OP_Gt:    res2 = res>0;      break;
> -	default:       res2 = res>=0;     break;
> -	}
> -
> -	/* Undo any changes made by mem_apply_type() to the input registers. */
> -	assert((pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn));
> -	pIn1->flags = flags1;
> -	pIn1->field_type = ft_p1;
> -	assert((pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn));
> -	pIn3->flags = flags3;
> -	pIn3->field_type = ft_p3;
> +	switch (pOp->opcode) {
> +	case OP_Eq:
> +		result = cmp_res == 0;
> +		break;
> +	case OP_Ne:
> +		result = cmp_res != 0;
> +		break;
> +	case OP_Lt:
> +		result = cmp_res < 0;
> +		break;
> +	case OP_Le:
> +		result = cmp_res <= 0;
> +		break;
> +	case OP_Gt:
> +		result = cmp_res > 0;
> +		break;
> +	case OP_Ge:
> +		result = cmp_res >= 0;
> +		break;
> +	default:
> +		unreachable();
> +	}
>  
>  	if (pOp->p5 & SQL_STOREP2) {
> -		iCompare = res;
> -		res2 = res2!=0;  /* For this path res2 must be exactly 0 or 1 */
> -		if ((pOp->p5 & SQL_KEEPNULL)!=0) {
> -			/* The KEEPNULL flag prevents OP_Eq from overwriting a NULL with true
> -			 * and prevents OP_Ne from overwriting NULL with false.  This flag
> -			 * is only used in contexts where either:
> -			 *   (1) op==OP_Eq && (r[P2]==NULL || r[P2]==0)
> -			 *   (2) op==OP_Ne && (r[P2]==NULL || r[P2]==1)
> -			 * Therefore it is not necessary to check the content of r[P2] for
> -			 * NULL.
> -			 */
> -			assert(pOp->opcode==OP_Ne || pOp->opcode==OP_Eq);
> -			assert(res2==0 || res2==1);
> -			testcase( res2==0 && pOp->opcode==OP_Eq);
> -			testcase( res2==1 && pOp->opcode==OP_Eq);
> -			testcase( res2==0 && pOp->opcode==OP_Ne);
> -			testcase( res2==1 && pOp->opcode==OP_Ne);
> -			if ((pOp->opcode==OP_Eq)==res2) break;
> +		iCompare = cmp_res;
> +		/*
> +		 * The KEEPNULL flag prevents OP_Eq from
> +		 * overwriting a NULL with true and prevents OP_Ne
> +		 * from overwriting NULL with false. This flag
> +		 * is only used in contexts where either:
> +		 *   (1) op==OP_Eq && (r[P2]==NULL || r[P2]==0)
> +		 *   (2) op==OP_Ne && (r[P2]==NULL || r[P2]==1)
> +		 * Therefore it is not necessary to check the
> +		 * content of r[P2] for NULL.
> +		 */
> +		if ((pOp->p5 & SQL_KEEPNULL) != 0) {

12. This condition and the comment clearly could be kept as is, since
only formatting is changed. Could you please preserve the old lines?
For the sake of git blame. Also check other places where it is possible
to keep the old lines for free (without necessity to make new code
worse).

> +			assert(pOp->opcode == OP_Ne || pOp->opcode == OP_Eq);
> +			if ((pOp->opcode == OP_Eq) == result)
> +				break;
>  		}
>  		pOut = vdbe_prepare_null_out(p, pOp->p2);
> -		mem_set_bool(pOut, res2);
> +		mem_set_bool(pOut, result);
>  		REGISTER_TRACE(p, pOp->p2, pOut);
>  	} else {
> -		VdbeBranchTaken(res!=0, (pOp->p5 & SQL_NULLEQ)?2:3);
> -		if (res2) {
> +		VdbeBranchTaken(cmp_res != 0, (pOp->p5 & SQL_NULLEQ) ? 2 : 3);
> +		if (result)
>  			goto jump_to_p2;
> -		}
>  	}
>  	break;
>  }> diff --git a/src/box/tuple_compare.cc b/src/box/tuple_compare.cc
> index 3f8a0ce..6cbf555 100644
> --- a/src/box/tuple_compare.cc
> +++ b/src/box/tuple_compare.cc
> @@ -104,6 +104,12 @@ mp_classof(enum mp_type type)
>  	return mp_classes[type];
>  }
>  
> +int
> +mp_type_classes_comp(enum mp_type ltype, enum mp_type rtype)
> +{
> +	return mp_classof(ltype) - mp_classof(rtype);
> +}

13. Probably better keep it in one single usage place. Since it adds
unnecessary dependency on msgpuck.h for tuple_compare.h.

> +
>  static enum mp_class
>  mp_extension_class(const char *data)
>  {
> diff --git a/test/sql-tap/tkt3493.test.lua b/test/sql-tap/tkt3493.test.lua
> index 7ceec47..e5d7b2f 100755
> --- a/test/sql-tap/tkt3493.test.lua
> +++ b/test/sql-tap/tkt3493.test.lua
> @@ -45,7 +45,7 @@ test:do_execsql_test(
>      [[
>          SELECT 
>            CASE 
> -             WHEN B.val = 1 THEN 'XYZ' 
> +             WHEN B.val = '1' THEN 'XYZ' 

14. Leading whitespace.

>               ELSE A.val 
>            END AS Col1
>          FROM B  
15. I propose to add some tests specific to the tickets we fix.
Probably remove some existing tests which test the same. With more
edge cases. gcov should help to check that all conditions in this
patch are covered, especially about preparations of Mem to be used
in a comparison.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Tarantool-patches] [PATCH v1 1/1] sql: remove implicit cast for COMPARISON
  2020-03-29 22:29 ` Vladislav Shpilevoy
@ 2020-03-30 11:38   ` Nikita Pettik
  2020-03-30 16:53     ` Mergen Imeev
  2020-04-21 12:42   ` Mergen Imeev
  1 sibling, 1 reply; 8+ messages in thread
From: Nikita Pettik @ 2020-03-30 11:38 UTC (permalink / raw)
  To: Vladislav Shpilevoy; +Cc: tarantool-patches

On 30 Mar 00:29, Vladislav Shpilevoy wrote:
> Hi! Thanks for the patch!
> 
> See 15 comments below.
> 
> I don't think I understood all the changed (because I am very out of
> context), so I will revisited many of them when you send v2.
> 
> On 20/03/2020 13:34, imeevma@tarantool.org wrote:
> > This patch removes implicit cast for comparison. Also, it make
> > search using an index work the same way as in case of fullscan in
> > most cases.
> > 
> > Closes #4230
> > Closes #4783
> > ---
> > https://github.com/tarantool/tarantool/issues/4230
> > https://github.com/tarantool/tarantool/issues/4783
> > https://github.com/tarantool/tarantool/tree/imeevma/gh-4230-remove-implicit-cast-for-index-search-second
> > 
> > @ChangeLog Remove implicit cast for comparison gh-4230
> 
> 1. Worth adding more details. What implicit cast? All of them?
> 
> Do we need a docbot request for this?

We definitely do need a docbot request. What is more, I'd explicitly
agree all user-visible changes introduced in this patch with Peter
Gulutzan. If Peter is already OK with it, Mergen, could you please
copy link to the corresponding mail (cause I've a bit lost in all
'cast' threads).
 
> > diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
> > index 1579cc9..cd626bd 100644
> > --- a/src/box/sql/sqlInt.h
> > +++ b/src/box/sql/sqlInt.h
> > @@ -1304,6 +1304,9 @@ enum trim_side_mask {
> >  				 (X) == FIELD_TYPE_UNSIGNED || \
> >  				 (X) == FIELD_TYPE_DOUBLE)
> >  
> > +#define sql_mp_type_is_numeric(X)  ((X) == MP_INT || (X) == MP_UINT || \
> > +				    (X) == MP_FLOAT || (X) == MP_DOUBLE)
> 
> 
> 7. Is there a ticket to stop conveting MEM_* to MP_*?

Hm, I thought I created once such ticket, but in fact failed to
find it. If you are OK with suggestion below concerning splitting
mem type into two members, I'll open an issue.

> MP_* now contains all MEM_* and even more, right?

Not exactly. There are also VDBE specific MEMs like
MEM_Frame, MEM_Cleared, MEM_TypeMask etc, and auxiliary
MEMs - MEM_Dyn, MEM_Static, MEM_Ephem (i.e. allocation policy),
MEM_Subtype, MEM_Agg and so forth. I guess still we can split
struct mem->type into mp_type and aux_flags.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Tarantool-patches] [PATCH v1 1/1] sql: remove implicit cast for COMPARISON
  2020-03-30 11:38   ` Nikita Pettik
@ 2020-03-30 16:53     ` Mergen Imeev
  2020-04-02 23:47       ` Vladislav Shpilevoy
  0 siblings, 1 reply; 8+ messages in thread
From: Mergen Imeev @ 2020-03-30 16:53 UTC (permalink / raw)
  To: Nikita Pettik; +Cc: tarantool-patches, Vladislav Shpilevoy

On Mon, Mar 30, 2020 at 11:38:06AM +0000, Nikita Pettik wrote:
> On 30 Mar 00:29, Vladislav Shpilevoy wrote:
> > Hi! Thanks for the patch!
> > 
> > See 15 comments below.
> > 
> > I don't think I understood all the changed (because I am very out of
> > context), so I will revisited many of them when you send v2.
> > 
> > On 20/03/2020 13:34, imeevma@tarantool.org wrote:
> > > This patch removes implicit cast for comparison. Also, it make
> > > search using an index work the same way as in case of fullscan in
> > > most cases.
> > > 
> > > Closes #4230
> > > Closes #4783
> > > ---
> > > https://github.com/tarantool/tarantool/issues/4230
> > > https://github.com/tarantool/tarantool/issues/4783
> > > https://github.com/tarantool/tarantool/tree/imeevma/gh-4230-remove-implicit-cast-for-index-search-second
> > > 
> > > @ChangeLog Remove implicit cast for comparison gh-4230
> > 
> > 1. Worth adding more details. What implicit cast? All of them?
> > 
> > Do we need a docbot request for this?
> 
> We definitely do need a docbot request. What is more, I'd explicitly
> agree all user-visible changes introduced in this patch with Peter
> Gulutzan. If Peter is already OK with it, Mergen, could you please
> copy link to the corresponding mail (cause I've a bit lost in all
> 'cast' threads).
>
Ok, I will do all these in the next version of the patch.

> > > diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
> > > index 1579cc9..cd626bd 100644
> > > --- a/src/box/sql/sqlInt.h
> > > +++ b/src/box/sql/sqlInt.h
> > > @@ -1304,6 +1304,9 @@ enum trim_side_mask {
> > >  				 (X) == FIELD_TYPE_UNSIGNED || \
> > >  				 (X) == FIELD_TYPE_DOUBLE)
> > >  
> > > +#define sql_mp_type_is_numeric(X)  ((X) == MP_INT || (X) == MP_UINT || \
> > > +				    (X) == MP_FLOAT || (X) == MP_DOUBLE)
> > 
> > 
> > 7. Is there a ticket to stop conveting MEM_* to MP_*?
> 
> Hm, I thought I created once such ticket, but in fact failed to
> find it. If you are OK with suggestion below concerning splitting
> mem type into two members, I'll open an issue.
> 
Does anyony mind if I do all this here, before main patch-set?

> > MP_* now contains all MEM_* and even more, right?
> 
> Not exactly. There are also VDBE specific MEMs like
> MEM_Frame, MEM_Cleared, MEM_TypeMask etc, and auxiliary
> MEMs - MEM_Dyn, MEM_Static, MEM_Ephem (i.e. allocation policy),
> MEM_Subtype, MEM_Agg and so forth. I guess still we can split
> struct mem->type into mp_type and aux_flags.
> 

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Tarantool-patches] [PATCH v1 1/1] sql: remove implicit cast for COMPARISON
  2020-03-30 16:53     ` Mergen Imeev
@ 2020-04-02 23:47       ` Vladislav Shpilevoy
  0 siblings, 0 replies; 8+ messages in thread
From: Vladislav Shpilevoy @ 2020-04-02 23:47 UTC (permalink / raw)
  To: Mergen Imeev, Nikita Pettik; +Cc: tarantool-patches

>>>> diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
>>>> index 1579cc9..cd626bd 100644
>>>> --- a/src/box/sql/sqlInt.h
>>>> +++ b/src/box/sql/sqlInt.h
>>>> @@ -1304,6 +1304,9 @@ enum trim_side_mask {
>>>>  				 (X) == FIELD_TYPE_UNSIGNED || \
>>>>  				 (X) == FIELD_TYPE_DOUBLE)
>>>>  
>>>> +#define sql_mp_type_is_numeric(X)  ((X) == MP_INT || (X) == MP_UINT || \
>>>> +				    (X) == MP_FLOAT || (X) == MP_DOUBLE)
>>>
>>>
>>> 7. Is there a ticket to stop conveting MEM_* to MP_*?
>>
>> Hm, I thought I created once such ticket, but in fact failed to
>> find it. If you are OK with suggestion below concerning splitting
>> mem type into two members, I'll open an issue.
>>
> Does anyony mind if I do all this here, before main patch-set?

I am ok with that. But you need to do it quick then, because
the release is close.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Tarantool-patches] [PATCH v1 1/1] sql: remove implicit cast for COMPARISON
  2020-03-29 22:29 ` Vladislav Shpilevoy
  2020-03-30 11:38   ` Nikita Pettik
@ 2020-04-21 12:42   ` Mergen Imeev
  2020-04-26 18:22     ` Vladislav Shpilevoy
  1 sibling, 1 reply; 8+ messages in thread
From: Mergen Imeev @ 2020-04-21 12:42 UTC (permalink / raw)
  To: Vladislav Shpilevoy; +Cc: tarantool-patches

Hi! Thank you for review. My answers and new patch below.
In this patch I removed part about SCALAR behaviour and
part that tries to remove difference in behaviour between
cases we use index and not. These both parts looks too
complicated here. And, now I am not sure that they should
be here. Also, I reduced number of changes in the patch.

On Mon, Mar 30, 2020 at 12:29:22AM +0200, Vladislav Shpilevoy wrote:
> Hi! Thanks for the patch!
> 
> See 15 comments below.
> 
> I don't think I understood all the changed (because I am very out of
> context), so I will revisited many of them when you send v2.
> 
> On 20/03/2020 13:34, imeevma@tarantool.org wrote:
> > This patch removes implicit cast for comparison. Also, it make
> > search using an index work the same way as in case of fullscan in
> > most cases.
> > 
> > Closes #4230
> > Closes #4783
> > ---
> > https://github.com/tarantool/tarantool/issues/4230
> > https://github.com/tarantool/tarantool/issues/4783
> > https://github.com/tarantool/tarantool/tree/imeevma/gh-4230-remove-implicit-cast-for-index-search-second
> > 
> > @ChangeLog Remove implicit cast for comparison gh-4230
> 
> 1. Worth adding more details. What implicit cast? All of them?
Even it say that all of them should be removed, actually it
removes only case from string to numbers and from numbers
to string.

> 
> Do we need a docbot request for this?
> 
Fixed, but not sure that I wrote enough.

> > diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
> > index 1579cc9..cd626bd 100644
> > --- a/src/box/sql/sqlInt.h
> > +++ b/src/box/sql/sqlInt.h
> > @@ -1304,6 +1304,9 @@ enum trim_side_mask {
> >  				 (X) == FIELD_TYPE_UNSIGNED || \
> >  				 (X) == FIELD_TYPE_DOUBLE)
> >  
> > +#define sql_mp_type_is_numeric(X)  ((X) == MP_INT || (X) == MP_UINT || \
> > +				    (X) == MP_FLOAT || (X) == MP_DOUBLE)
> 
> 2. Better make it static inline function.
> 
Removed.

> > diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
> > index e8a029a..8c95fd4 100644
> > --- a/src/box/sql/vdbe.c
> > +++ b/src/box/sql/vdbe.c
> > @@ -660,6 +660,216 @@ vdbe_field_ref_fetch_field(struct vdbe_field_ref *field_ref, uint32_t fieldno)
> >  }
> >  
> >  /**
> > + * Prepare mem to use for comparison with value with type UNSIGNED
> > + * from index.
> > + *
> > + * @param[out] mem Mem to prepare for comparison.
> > + * @param[in][out] op Operation that was before preperation and
> > + *                 operation after.
> 
> 3. preperation -> preparation. The same in the next functions.
> 
Removed.

> > + * @param is_eq True if operation was EQ.
> > + * @param[out] is_none True if nothing will be found.
> > + * @retval 0 on success.
> > + * @retval -1 on error.
> > + */
> > +static int
> > +sql_mem_to_unsigned_for_comp(struct Mem *mem, uint32_t *op, int is_eq,
> 
> 4. Opcode has type u8 in UnpackedRecord. Better make it the
> same here. The same in other places.
> 
Removed.

> 5. is_eq is a flag, and therefore should be a boolean. The
> same in the next functions.
> 
Removed.

> > +			     bool *is_none)
> > +{
> > +	assert(*is_none == false);> +	uint32_t orig_op = *op;
> > +	enum mp_type mp_type = sql_value_type(mem);
> > +	assert(mp_type == MP_DOUBLE || mp_type == MP_INT);
> > +	if (mp_type == MP_INT || mem->u.r < 0) {
> > +		if (orig_op == OP_SeekGE || orig_op == OP_SeekGT) {
> > +			mem_set_u64(mem, 0);
> > +			*op = OP_SeekGE;
> > +			return 0;
> > +		}
> > +		*is_none = true;
> > +		return 0;
> > +	}
> > +	double d = mem->u.r;
> > +	if (d >= UINT64_MAX) {
> > +		if (orig_op == OP_SeekLE || orig_op == OP_SeekLT) {
> > +			mem_set_u64(mem, UINT64_MAX);
> > +			*op = OP_SeekLE;
> > +			return 0;
> > +		}
> > +		*is_none = true;
> > +		return 0;
> > +	}
> > +	uint64_t u = (uint64_t)d;
> > +	if (d != u && is_eq) {
> > +		*is_none = true;
> > +		return 0;
> > +	}
> > +	mem_set_u64(mem, u);
> > +	if (d == u)
> > +		return 0;
> > +	if (orig_op == OP_SeekGE)
> > +		*op = OP_SeekGT;
> > +	else if (orig_op == OP_SeekLT)
> > +		*op = OP_SeekLE;
> > +	return 0;
> > +}
> > +
> > +/**
> > + * Prepare mem to use for comparison with value with type INTEGER
> > + * from index.
> > + *
> > + * @param[out] mem Mem to prepare for comparison.
> > + * @param[in][out] op Operation that was before preperation and
> > + *                 operation after.
> > + * @param is_eq True if operation was EQ.
> > + * @param[out] is_none True if nothing will be found.
> > + * @retval 0 on success.
> > + * @retval -1 on error.
> > + */
> > +static int
> > +sql_mem_to_integer_for_comp(struct Mem *mem, uint32_t *op, int is_eq,
> > +			    bool *is_none)
> > +{
> > +	assert(*is_none == false);
> > +	uint32_t orig_op = *op;
> > +	assert(sql_value_type(mem) == MP_DOUBLE);
> > +	double d = mem->u.r;
> > +	if (d < INT64_MIN) {
> > +		if (orig_op == OP_SeekGE || orig_op == OP_SeekGT) {
> > +			mem_set_i64(mem, INT64_MIN);
> > +			*op = OP_SeekGE;
> > +			return 0;
> > +		}
> > +		*is_none = true;
> > +		return 0;
> > +	}
> > +	if (d >= UINT64_MAX) {
> > +		if (orig_op == OP_SeekLE || orig_op == OP_SeekLT) {
> > +			mem_set_u64(mem, UINT64_MAX);
> > +			*op = OP_SeekLE;
> > +			return 0;
> > +		}
> > +		*is_none = true;
> > +		return 0;
> > +	}
> > +	int64_t i = (int64_t)d;
> > +	uint64_t u = (uint64_t)d;
> > +	if (d != i && d != u && is_eq) {
> > +		*is_none = true;
> > +		return 0;
> > +	}
> > +	if (d > 0)
> 
> 6. >= 0?
> 
Removed.

> > +		mem_set_u64(mem, u);
> > +	else
> > +		mem_set_i64(mem, i);
> > +	if (d == u || d == i)
> > +		return 0;
> > +	if (d >= 0) {
> > +		if (orig_op == OP_SeekGE)
> > +			*op = OP_SeekGT;
> > +		else if (orig_op == OP_SeekLT)
> > +			*op = OP_SeekLE;
> > +		return 0;
> > +	}
> > +	if (orig_op == OP_SeekLE)
> > +		*op = OP_SeekLT;
> > +	else if (orig_op == OP_SeekGT)
> > +		*op = OP_SeekGE;
> > +	return 0;
> > +}
> > +
> > +/**
> > + * Prepare mem to use for comparison with value with type DOUBLE
> > + * from index.
> > + *
> > + * @param[out] mem Mem to prepare for comparison.
> > + * @param[in][out] op Operation that was before preperation and
> > + *                 operation after.
> > + * @param is_eq True if operation was EQ.
> > + * @param[out] is_none True if nothing will be found.
> > + * @retval 0 on success.
> > + * @retval -1 on error.
> > + */
> > +static int
> > +sql_mem_to_double_for_comp(struct Mem *mem, uint32_t *op, int is_eq,
> > +			   bool *is_none)
> > +{
> > +	assert(*is_none == false);
> > +	uint32_t orig_op = *op;
> > +	enum mp_type mp_type = sql_value_type(mem);
> 
> 7. Is there a ticket to stop conveting MEM_* to MP_*? MP_* now
> contains all MEM_* and even more, right?
> 
I created an issue: #4906. I'm sorry, I wanted to fix it
here, but decided to leave it for later since it took me
too long to make new version of this patch.

> > +	assert(mp_type == MP_INT || mp_type == MP_UINT);
> > +	int64_t i = mem->u.i;
> > +	uint64_t u = mem->u.u;
> > +	/* 2^53 == 9007199254740992 */
> > +	if (mp_type == MP_INT && i > -9007199254740992) {
> 
> 8. Is it possible to replace this with 'i == (int64)(double)i' ?
> The same below. Because these double vs int are always tricky.
> And I would like to avoid any constant assumptions here. For
> example, you excluded 2^53, but 2^53 can be stored (from what I
> saw and tested). So it would be more correct to write >= -9007199254740992,
> not >. However the 2-cast solution may work too, and does not
> use constants.
> 
Removed.

> > +		sqlVdbeMemSetDouble(mem, i);
> > +		return 0;
> > +	} else if (mp_type == MP_UINT && u < 9007199254740992) {
> > +		sqlVdbeMemSetDouble(mem, u);
> > +		return 0;
> > +	}
> > +
> > +	double d = mp_type == MP_INT ? (double)i : (double)u;
> > +	if (is_eq) {
> > +		if (i != d && u != d)
> > +			*is_none = true;
> > +		else
> > +			sqlVdbeMemSetDouble(mem, d);
> > +		return 0;
> > +	}
> > +
> > +	sqlVdbeMemSetDouble(mem, d);
> > +	if (mp_type == MP_INT) {
> > +		if (orig_op == OP_SeekGT && d > i)
> > +			*op = OP_SeekGE;
> > +		else if (orig_op == OP_SeekGE && d < i)
> > +			*op = OP_SeekGT;
> > +		else if (orig_op == OP_SeekLT && d < i)
> > +			*op = OP_SeekLE;
> > +		else if (orig_op == OP_SeekLE && d > i)
> > +			*op = OP_SeekLT;
> > +		return 0;
> > +	}
> > +	if (orig_op == OP_SeekGT && d > u)
> > +		*op = OP_SeekGE;
> > +	else if (orig_op == OP_SeekGE && d < u)
> > +		*op = OP_SeekGT;
> > +	else if (orig_op == OP_SeekLT && d < u)
> > +		*op = OP_SeekLE;
> > +	else if (orig_op == OP_SeekLE && d > u)
> > +		*op = OP_SeekLT;
> > +	return 0;
> > +}
> > +
> > +/**
> > + * Prepare mem to use for comparison with value with numeric type
> 
> 9. No mem among the arguments.
> 
Removed.

> > + * from index.
> > + *
> > + * @param[in][out] r Unpacked tuple that should be prepared for
> > + *                 comparison.
> > + * @param i field of unpacked tuple that should be prepared.
> > + * @param is_eq True if operation was EQ.
> > + * @param[out] is_none True if nothing will be found.
> > + * @retval 0 on success.
> > + * @retval -1 on error.
> > + */
> > +static int
> > +sql_prepare_rec_for_comp(struct UnpackedRecord *r, int i, int is_eq,
> > +			 bool *is_none)
> > +{
> > +	struct Mem *mem = &r->aMem[i];
> > +	enum field_type field_type = r->key_def->parts[i].type;
> > +	uint32_t opcode = r->opcode;
> > +	if (field_type == FIELD_TYPE_UNSIGNED)
> > +		sql_mem_to_unsigned_for_comp(mem, &opcode, is_eq, is_none);
> > +	else if (field_type == FIELD_TYPE_INTEGER)
> > +		sql_mem_to_integer_for_comp(mem, &opcode, is_eq, is_none);
> > +	else
> > +		sql_mem_to_double_for_comp(mem, &opcode, is_eq, is_none);
> > +	r->opcode = opcode;
> > +	return 0;
> > +}
> > @@ -2133,189 +2336,109 @@ case OP_Lt:               /* same as TK_LT, jump, in1, in3 */
> >  case OP_Le:               /* same as TK_LE, jump, in1, in3 */
> >  case OP_Gt:               /* same as TK_GT, jump, in1, in3 */
> >  case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
> > -	int res, res2;      /* Result of the comparison of pIn1 against pIn3 */
> > -	u32 flags1;         /* Copy of initial value of pIn1->flags */
> > -	u32 flags3;         /* Copy of initial value of pIn3->flags */
> > -
> > +	/*
> > +	 * Result of comparison: more than 0 if l > r,
> > +	 * 0 if l == r, less than 0 if l < r.
> > +	 */
> > +	int cmp_res;
> > +	/* Result of the operation. */
> > +	bool result;
> >  	pIn1 = &aMem[pOp->p1];
> >  	pIn3 = &aMem[pOp->p3];
> > -	flags1 = pIn1->flags;
> > -	flags3 = pIn3->flags;
> > -	enum field_type ft_p1 = pIn1->field_type;
> > -	enum field_type ft_p3 = pIn3->field_type;
> > -	if ((flags1 | flags3)&MEM_Null) {
> > -		/* One or both operands are NULL */
> > -		if (pOp->p5 & SQL_NULLEQ) {
> > -			/* If SQL_NULLEQ is set (which will only happen if the operator is
> > -			 * OP_Eq or OP_Ne) then take the jump or not depending on whether
> > -			 * or not both operands are null.
> > -			 */
> > -			assert(pOp->opcode==OP_Eq || pOp->opcode==OP_Ne);
> > -			assert((flags1 & MEM_Cleared)==0);
> > -			assert((pOp->p5 & SQL_JUMPIFNULL)==0);
> > -			if ((flags1&flags3&MEM_Null)!=0
> > -			    && (flags3&MEM_Cleared)==0
> > -				) {
> > -				res = 0;  /* Operands are equal */
> > -			} else {
> > -				res = 1;  /* Operands are not equal */
> > -			}
> > -		} else {
> > -			/* SQL_NULLEQ is clear and at least one operand is NULL,
> > -			 * then the result is always NULL.
> > -			 * The jump is taken if the SQL_JUMPIFNULL bit is set.
> > +
> > +	bool has_scalar = (pIn1->field_type == FIELD_TYPE_SCALAR) ||
> > +			  (pIn3->field_type == FIELD_TYPE_SCALAR);
> > +	enum mp_type ltype = sql_value_type(pIn1);
> > +	enum mp_type rtype = sql_value_type(pIn3);
> > +	assert(ltype != MP_MAP && rtype != MP_MAP);
> > +	assert(ltype != MP_ARRAY && rtype != MP_ARRAY);
> > +	int mp_classes_comp = mp_type_classes_comp(rtype, ltype);
> > +
> > +	if (ltype == MP_NIL || rtype == MP_NIL) {
> > +		if ((pOp->p5 & SQL_NULLEQ) == 0) {
> > +			/*
> > +			 * SQL_NULLEQ is clear and at least one
> > +			 * operand is NULL, then the result is
> > +			 * always NULL. The jump is taken if the
> > +			 * SQL_JUMPIFNULL bit is set.
> >  			 */
> >  			if (pOp->p5 & SQL_STOREP2) {
> >  				pOut = vdbe_prepare_null_out(p, pOp->p2);
> > -				iCompare = 1;    /* Operands are not equal */
> > +				iCompare = 1;
> >  				REGISTER_TRACE(p, pOp->p2, pOut);
> >  			} else {
> >  				VdbeBranchTaken(2,3);
> > -				if (pOp->p5 & SQL_JUMPIFNULL) {
> > +				if (pOp->p5 & SQL_JUMPIFNULL)
> >  					goto jump_to_p2;
> > -				}
> 
> 10. I know these places violated our style, but lets keep
> them. Since they are not stictly related to the patch. We will
> have a chance to fix them later.
> 
Fixed.

> >  			}
> >  			break;
> >  		}
> > -	} else if (((flags1 | flags3) & MEM_Bool) != 0 ||
> > -		   ((flags1 | flags3) & MEM_Blob) != 0) {
> >  		/*
> > -		 * If one of values is of type BOOLEAN or VARBINARY,
> > -		 * then the second one must be of the same type as
> > -		 * well. Otherwise an error is raised.
> > +		 * If SQL_NULLEQ is set (which will only happen if
> > +		 * the operator is OP_Eq or OP_Ne) then take the
> > +		 * jump or not depending on whether or not both
> > +		 * operands are null.
> >  		 */
> > -		int type_arg1 = flags1 & (MEM_Bool | MEM_Blob);
> > -		int type_arg3 = flags3 & (MEM_Bool | MEM_Blob);
> > -		if (type_arg1 != type_arg3) {
> > -			char *inconsistent_type = type_arg1 != 0 ?
> > -						  mem_type_to_str(pIn3) :
> > -						  mem_type_to_str(pIn1);
> > -			char *expected_type     = type_arg1 != 0 ?
> > -						  mem_type_to_str(pIn1) :
> > -						  mem_type_to_str(pIn3);
> > -			diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
> > -				 inconsistent_type, expected_type);
> > -			goto abort_due_to_error;
> > -		}
> > -		res = sqlMemCompare(pIn3, pIn1, NULL);
> > +		assert(pOp->opcode == OP_Eq || pOp->opcode == OP_Ne);
> > +		assert((pOp->p5 & SQL_JUMPIFNULL) == 0);
> > +		cmp_res = !(ltype == MP_NIL && rtype == MP_NIL);
> 
> 11. The compiler is likely to help us here, but still lets apply '!'.
> It will look
> 
>     ltype != MP_NIL || rtype != MP_NIL
> 
Removed.

> > +	} else if (mp_classes_comp == 0) {
> > +		cmp_res = sqlMemCompare(pIn3, pIn1, pOp->p4.pColl);
> > +	} else if (has_scalar) {
> > +		cmp_res = mp_classes_comp;
> >  	} else {
> > -		enum field_type type = pOp->p5 & FIELD_TYPE_MASK;
> > -		if (sql_type_is_numeric(type)) {
> > -			if ((flags1 | flags3)&MEM_Str) {
> > -				if ((flags1 & MEM_Str) == MEM_Str) {
> > -					mem_apply_numeric_type(pIn1);
> > -					testcase( flags3!=pIn3->flags); /* Possible if pIn1==pIn3 */
> > -					flags3 = pIn3->flags;
> > -				}
> > -				if ((flags3 & MEM_Str) == MEM_Str) {
> > -					if (mem_apply_numeric_type(pIn3) != 0) {
> > -						diag_set(ClientError,
> > -							 ER_SQL_TYPE_MISMATCH,
> > -							 sql_value_to_diag_str(pIn3),
> > -							 "numeric");
> > -						goto abort_due_to_error;
> > -					}
> > +		diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
> > +			 mem_type_to_str(pIn1), mem_type_to_str(pIn3));
> > +		goto abort_due_to_error;
> > +	}
> >  
> > -				}
> > -			}
> > -			/* Handle the common case of integer comparison here, as an
> > -			 * optimization, to avoid a call to sqlMemCompare()
> > -			 */
> > -			if ((pIn1->flags & pIn3->flags & (MEM_Int | MEM_UInt)) != 0) {
> > -				if ((pIn1->flags & pIn3->flags & MEM_Int) != 0) {
> > -					if (pIn3->u.i > pIn1->u.i)
> > -						res = +1;
> > -					else if (pIn3->u.i < pIn1->u.i)
> > -						res = -1;
> > -					else
> > -						res = 0;
> > -					goto compare_op;
> > -				}
> > -				if ((pIn1->flags & pIn3->flags & MEM_UInt) != 0) {
> > -					if (pIn3->u.u > pIn1->u.u)
> > -						res = +1;
> > -					else if (pIn3->u.u < pIn1->u.u)
> > -						res = -1;
> > -					else
> > -						res = 0;
> > -					goto compare_op;
> > -				}
> > -				if ((pIn1->flags & MEM_UInt) != 0 &&
> > -				    (pIn3->flags & MEM_Int) != 0) {
> > -					res = -1;
> > -					goto compare_op;
> > -				}
> > -				res = 1;
> > -				goto compare_op;
> > -			}
> > -		} else if (type == FIELD_TYPE_STRING) {
> > -			if ((flags1 & MEM_Str) == 0 &&
> > -			    (flags1 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
> > -				testcase( pIn1->flags & MEM_Int);
> > -				testcase( pIn1->flags & MEM_Real);
> > -				sqlVdbeMemStringify(pIn1);
> > -				testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn));
> > -				flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
> > -				assert(pIn1!=pIn3);
> > -			}
> > -			if ((flags3 & MEM_Str) == 0 &&
> > -			    (flags3 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
> > -				testcase( pIn3->flags & MEM_Int);
> > -				testcase( pIn3->flags & MEM_Real);
> > -				sqlVdbeMemStringify(pIn3);
> > -				testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn));
> > -				flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & MEM_TypeMask);
> > -			}
> > -		}
> > -		assert(pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0);
> > -		res = sqlMemCompare(pIn3, pIn1, pOp->p4.pColl);
> > -	}
> > -			compare_op:
> > -	switch( pOp->opcode) {
> > -	case OP_Eq:    res2 = res==0;     break;
> > -	case OP_Ne:    res2 = res;        break;
> > -	case OP_Lt:    res2 = res<0;      break;
> > -	case OP_Le:    res2 = res<=0;     break;
> > -	case OP_Gt:    res2 = res>0;      break;
> > -	default:       res2 = res>=0;     break;
> > -	}
> > -
> > -	/* Undo any changes made by mem_apply_type() to the input registers. */
> > -	assert((pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn));
> > -	pIn1->flags = flags1;
> > -	pIn1->field_type = ft_p1;
> > -	assert((pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn));
> > -	pIn3->flags = flags3;
> > -	pIn3->field_type = ft_p3;
> > +	switch (pOp->opcode) {
> > +	case OP_Eq:
> > +		result = cmp_res == 0;
> > +		break;
> > +	case OP_Ne:
> > +		result = cmp_res != 0;
> > +		break;
> > +	case OP_Lt:
> > +		result = cmp_res < 0;
> > +		break;
> > +	case OP_Le:
> > +		result = cmp_res <= 0;
> > +		break;
> > +	case OP_Gt:
> > +		result = cmp_res > 0;
> > +		break;
> > +	case OP_Ge:
> > +		result = cmp_res >= 0;
> > +		break;
> > +	default:
> > +		unreachable();
> > +	}
> >  
> >  	if (pOp->p5 & SQL_STOREP2) {
> > -		iCompare = res;
> > -		res2 = res2!=0;  /* For this path res2 must be exactly 0 or 1 */
> > -		if ((pOp->p5 & SQL_KEEPNULL)!=0) {
> > -			/* The KEEPNULL flag prevents OP_Eq from overwriting a NULL with true
> > -			 * and prevents OP_Ne from overwriting NULL with false.  This flag
> > -			 * is only used in contexts where either:
> > -			 *   (1) op==OP_Eq && (r[P2]==NULL || r[P2]==0)
> > -			 *   (2) op==OP_Ne && (r[P2]==NULL || r[P2]==1)
> > -			 * Therefore it is not necessary to check the content of r[P2] for
> > -			 * NULL.
> > -			 */
> > -			assert(pOp->opcode==OP_Ne || pOp->opcode==OP_Eq);
> > -			assert(res2==0 || res2==1);
> > -			testcase( res2==0 && pOp->opcode==OP_Eq);
> > -			testcase( res2==1 && pOp->opcode==OP_Eq);
> > -			testcase( res2==0 && pOp->opcode==OP_Ne);
> > -			testcase( res2==1 && pOp->opcode==OP_Ne);
> > -			if ((pOp->opcode==OP_Eq)==res2) break;
> > +		iCompare = cmp_res;
> > +		/*
> > +		 * The KEEPNULL flag prevents OP_Eq from
> > +		 * overwriting a NULL with true and prevents OP_Ne
> > +		 * from overwriting NULL with false. This flag
> > +		 * is only used in contexts where either:
> > +		 *   (1) op==OP_Eq && (r[P2]==NULL || r[P2]==0)
> > +		 *   (2) op==OP_Ne && (r[P2]==NULL || r[P2]==1)
> > +		 * Therefore it is not necessary to check the
> > +		 * content of r[P2] for NULL.
> > +		 */
> > +		if ((pOp->p5 & SQL_KEEPNULL) != 0) {
> 
> 12. This condition and the comment clearly could be kept as is, since
> only formatting is changed. Could you please preserve the old lines?
> For the sake of git blame. Also check other places where it is possible
> to keep the old lines for free (without necessity to make new code
> worse).
> 
Fixed.

> > +			assert(pOp->opcode == OP_Ne || pOp->opcode == OP_Eq);
> > +			if ((pOp->opcode == OP_Eq) == result)
> > +				break;
> >  		}
> >  		pOut = vdbe_prepare_null_out(p, pOp->p2);
> > -		mem_set_bool(pOut, res2);
> > +		mem_set_bool(pOut, result);
> >  		REGISTER_TRACE(p, pOp->p2, pOut);
> >  	} else {
> > -		VdbeBranchTaken(res!=0, (pOp->p5 & SQL_NULLEQ)?2:3);
> > -		if (res2) {
> > +		VdbeBranchTaken(cmp_res != 0, (pOp->p5 & SQL_NULLEQ) ? 2 : 3);
> > +		if (result)
> >  			goto jump_to_p2;
> > -		}
> >  	}
> >  	break;
> >  }> diff --git a/src/box/tuple_compare.cc b/src/box/tuple_compare.cc
> > index 3f8a0ce..6cbf555 100644
> > --- a/src/box/tuple_compare.cc
> > +++ b/src/box/tuple_compare.cc
> > @@ -104,6 +104,12 @@ mp_classof(enum mp_type type)
> >  	return mp_classes[type];
> >  }
> >  
> > +int
> > +mp_type_classes_comp(enum mp_type ltype, enum mp_type rtype)
> > +{
> > +	return mp_classof(ltype) - mp_classof(rtype);
> > +}
> 
> 13. Probably better keep it in one single usage place. Since it adds
> unnecessary dependency on msgpuck.h for tuple_compare.h.
> 
Removed.

> > +
> >  static enum mp_class
> >  mp_extension_class(const char *data)
> >  {
> > diff --git a/test/sql-tap/tkt3493.test.lua b/test/sql-tap/tkt3493.test.lua
> > index 7ceec47..e5d7b2f 100755
> > --- a/test/sql-tap/tkt3493.test.lua
> > +++ b/test/sql-tap/tkt3493.test.lua
> > @@ -45,7 +45,7 @@ test:do_execsql_test(
> >      [[
> >          SELECT 
> >            CASE 
> > -             WHEN B.val = 1 THEN 'XYZ' 
> > +             WHEN B.val = '1' THEN 'XYZ' 
> 
> 14. Leading whitespace.
> 
Removed.

> >               ELSE A.val 
> >            END AS Col1
> >          FROM B  
> 15. I propose to add some tests specific to the tickets we fix.
> Probably remove some existing tests which test the same. With more
> edge cases. gcov should help to check that all conditions in this
> patch are covered, especially about preparations of Mem to be used
> in a comparison.
Done.


New patch:


From 58f7b0ee9e840c00d3742a59eb6f660b0dbb213e Mon Sep 17 00:00:00 2001
From: Mergen Imeev <imeevma@gmail.com>
Date: Thu, 16 Apr 2020 12:52:59 +0300
Subject: [PATCH] sql: remove implicit cast from string for comparison

This patch removes implicit cast from strings to numbers for
comparison.

Part of #4230

@TarantoolBot document
Title: remove implicit cast from string to number

After this patch implicit cast from string to number and from
number to string is removed for COMPARISON.

Example:

tarantool> box.execute([[SELECT '1' > 0;]])
---
- null
- 'Type mismatch: can not convert 1 to numeric'
...

tarantool> box.execute([[SELECT "id" FROM "_space" WHERE '1' > "id";]])
---
- null
- 'Type mismatch: can not convert text to unsigned'
...

diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 724bc18..34bd38d 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -2209,22 +2209,17 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
 	} else {
 		enum field_type type = pOp->p5 & FIELD_TYPE_MASK;
 		if (sql_type_is_numeric(type)) {
-			if ((flags1 | flags3)&MEM_Str) {
-				if ((flags1 & MEM_Str) == MEM_Str) {
-					mem_apply_numeric_type(pIn1);
-					testcase( flags3!=pIn3->flags); /* Possible if pIn1==pIn3 */
-					flags3 = pIn3->flags;
-				}
-				if ((flags3 & MEM_Str) == MEM_Str) {
-					if (mem_apply_numeric_type(pIn3) != 0) {
-						diag_set(ClientError,
-							 ER_SQL_TYPE_MISMATCH,
-							 sql_value_to_diag_str(pIn3),
-							 "numeric");
-						goto abort_due_to_error;
-					}
-
-				}
+			if ((flags1 & MEM_Str) == MEM_Str) {
+				diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+					 sql_value_to_diag_str(pIn1),
+					 "numeric");
+				goto abort_due_to_error;
+			}
+			if ((flags3 & MEM_Str) == MEM_Str) {
+				diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+					 sql_value_to_diag_str(pIn3),
+					 "numeric");
+				goto abort_due_to_error;
 			}
 			/* Handle the common case of integer comparison here, as an
 			 * optimization, to avoid a call to sqlMemCompare()
@@ -2257,22 +2252,17 @@ case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
 				goto compare_op;
 			}
 		} else if (type == FIELD_TYPE_STRING) {
-			if ((flags1 & MEM_Str) == 0 &&
-			    (flags1 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
-				testcase( pIn1->flags & MEM_Int);
-				testcase( pIn1->flags & MEM_Real);
-				sqlVdbeMemStringify(pIn1);
-				testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn));
-				flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
-				assert(pIn1!=pIn3);
+			if ((flags1 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
+				diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+					 mem_type_to_str(pIn3),
+					 mem_type_to_str(pIn1));
+				goto abort_due_to_error;
 			}
-			if ((flags3 & MEM_Str) == 0 &&
-			    (flags3 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
-				testcase( pIn3->flags & MEM_Int);
-				testcase( pIn3->flags & MEM_Real);
-				sqlVdbeMemStringify(pIn3);
-				testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn));
-				flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & MEM_TypeMask);
+			if ((flags3 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
+				diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+					 mem_type_to_str(pIn1),
+					 mem_type_to_str(pIn3));
+				goto abort_due_to_error;
 			}
 		}
 		assert(pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0);
@@ -3377,8 +3367,6 @@ case OP_SeekGT: {       /* jump, in3 */
 		pIn3 = &aMem[int_field];
 		if ((pIn3->flags & MEM_Null) != 0)
 			goto skip_truncate;
-		if ((pIn3->flags & MEM_Str) != 0)
-			mem_apply_numeric_type(pIn3);
 		int64_t i;
 		if ((pIn3->flags & MEM_Int) == MEM_Int) {
 			i = pIn3->u.i;
@@ -3471,6 +3459,26 @@ skip_truncate:
 	assert(oc!=OP_SeekLT || r.default_rc==+1);
 
 	r.aMem = &aMem[pOp->p3];
+	for (int i = 0; i < r.nField; ++i) {
+		enum field_type type = r.key_def->parts[i].type;
+		struct Mem *mem = &r.aMem[i];
+		if ((mem->flags & MEM_Str) != 0 && sql_type_is_numeric(type)) {
+			diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+				field_type_strs[type], mem_type_to_str(mem));
+			goto abort_due_to_error;
+		}
+		if (mem_apply_type(mem, type) != 0) {
+			diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+				field_type_strs[type], mem_type_to_str(mem));
+			goto abort_due_to_error;
+		}
+		if ((mem->flags & MEM_Real) != 0 &&
+		    (type == FIELD_TYPE_INTEGER ||
+		     type == FIELD_TYPE_UNSIGNED)) {
+			res = 1;
+			goto seek_not_found;
+		}
+	}
 #ifdef SQL_DEBUG
 	{ int i; for(i=0; i<r.nField; i++) assert(memIsValid(&r.aMem[i])); }
 #endif
@@ -4598,6 +4606,27 @@ case OP_IdxGE:  {       /* jump */
 		r.default_rc = 0;
 	}
 	r.aMem = &aMem[pOp->p3];
+	for (int i = 0; i < r.nField; ++i) {
+		struct Mem *mem = &r.aMem[i];
+		enum mp_type mp_type = sql_value_type(mem);
+		enum field_type field_type = r.key_def->parts[i].type;
+		if (field_type == FIELD_TYPE_SCALAR ||
+		    mem->field_type == FIELD_TYPE_SCALAR)
+			continue;
+		bool is_nullable = r.key_def->parts[i].nullable_action ==
+				   ON_CONFLICT_ACTION_NONE;
+		if (field_mp_plain_type_is_compatible(field_type, mp_type,
+						      is_nullable))
+			continue;
+		if (!sql_type_is_numeric(field_type) ||
+		    !(mp_type == MP_INT || mp_type == MP_UINT ||
+		      mp_type == MP_DOUBLE || mp_type == MP_FLOAT)) {
+			diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+				 mem_type_to_str(mem),
+				 field_type_strs[field_type]);
+			goto abort_due_to_error;
+		}
+	}
 #ifdef SQL_DEBUG
 	{ int i; for(i=0; i<r.nField; i++) assert(memIsValid(&r.aMem[i])); }
 #endif
diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c
index 5bc27f1..1d7c766 100644
--- a/src/box/sql/wherecode.c
+++ b/src/box/sql/wherecode.c
@@ -335,72 +335,6 @@ disableTerm(WhereLevel * pLevel, WhereTerm * pTerm)
 	}
 }
 
-/**
- * Code an OP_ApplyType opcode to apply the column type string
- * @types to the n registers starting at @base.
- *
- * As an optimization, SCALAR entries (which are no-ops) at the
- * beginning and end of @types are ignored.  If all entries in
- * @types are SCALAR, then no code gets generated.
- *
- * This routine makes its own copy of @types so that the caller is
- * free to modify @types after this routine returns.
- */
-static void
-emit_apply_type(Parse *pParse, int base, int n, enum field_type *types)
-{
-	Vdbe *v = pParse->pVdbe;
-	if (types == NULL) {
-		assert(pParse->db->mallocFailed);
-		return;
-	}
-	assert(v != 0);
-
-	/*
-	 * Adjust base and n to skip over SCALAR entries at the
-	 * beginning and end of the type sequence.
-	 */
-	while (n > 0 && types[0] == FIELD_TYPE_SCALAR) {
-		n--;
-		base++;
-		types++;
-	}
-	while (n > 1 && types[n - 1] == FIELD_TYPE_SCALAR) {
-		n--;
-	}
-
-	if (n > 0) {
-		enum field_type *types_dup = field_type_sequence_dup(pParse,
-								     types, n);
-		sqlVdbeAddOp4(v, OP_ApplyType, base, n, 0,
-				  (char *) types_dup, P4_DYNAMIC);
-		sql_expr_type_cache_change(pParse, base, n);
-	}
-}
-
-/**
- * Expression @rhs, which is the RHS of a comparison operation, is
- * either a vector of n elements or, if n==1, a scalar expression.
- * Before the comparison operation, types @types are to be applied
- * to the @rhs values. This function modifies entries within the
- * field sequence to SCALAR if either:
- *
- *   * the comparison will be performed with no type, or
- *   * the type change in @types is guaranteed not to change the value.
- */
-static void
-expr_cmp_update_rhs_type(struct Expr *rhs, int n, enum field_type *types)
-{
-	for (int i = 0; i < n; i++) {
-		Expr *p = sqlVectorFieldSubexpr(rhs, i);
-		enum field_type expr_type = sql_expr_type(p);
-		if (sql_type_result(expr_type, types[i]) == FIELD_TYPE_SCALAR ||
-		    sql_expr_needs_no_type_change(p, types[i])) {
-			types[i] = FIELD_TYPE_SCALAR;
-		}
-	}
-}
-
 /*
  * Generate code for a single equality term of the WHERE clause.  An equality
  * term can be either X=expr or X IN (...).   pTerm is the term to be
@@ -644,8 +578,7 @@ static int
 codeAllEqualityTerms(Parse * pParse,	/* Parsing context */
 		     WhereLevel * pLevel,	/* Which nested loop of the FROM we are coding */
 		     int bRev,		/* Reverse the order of IN operators */
-		     int nExtraReg,	/* Number of extra registers to allocate */
-		     enum field_type **res_type)
+		     int nExtraReg)	/* Number of extra registers to allocate */
 {
 	u16 nEq;		/* The number of == or IN constraints to code */
 	u16 nSkip;		/* Number of left-most columns to skip */
@@ -669,9 +602,6 @@ codeAllEqualityTerms(Parse * pParse,	/* Parsing context */
 	nReg = pLoop->nEq + nExtraReg;
 	pParse->nMem += nReg;
 
-	enum field_type *type = sql_index_type_str(pParse->db, idx_def);
-	assert(type != NULL || pParse->db->mallocFailed);
-
 	if (nSkip) {
 		int iIdxCur = pLevel->iIdxCur;
 		sqlVdbeAddOp1(v, (bRev ? OP_Last : OP_Rewind), iIdxCur);
@@ -714,17 +644,7 @@ codeAllEqualityTerms(Parse * pParse,	/* Parsing context */
 				sqlVdbeAddOp2(v, OP_SCopy, r1, regBase + j);
 			}
 		}
-		if (pTerm->eOperator & WO_IN) {
-			if (pTerm->pExpr->flags & EP_xIsSelect) {
-				/* No type ever needs to be (or should be) applied to a value
-				 * from the RHS of an "? IN (SELECT ...)" expression. The
-				 * sqlFindInIndex() routine has already ensured that the
-				 * type of the comparison has been applied to the value.
-				 */
-				if (type != NULL)
-					type[j] = FIELD_TYPE_SCALAR;
-			}
-		} else if ((pTerm->eOperator & WO_ISNULL) == 0) {
+		if ((pTerm->eOperator & (WO_IN | WO_ISNULL)) == 0) {
 			Expr *pRight = pTerm->pExpr->pRight;
 			if (sqlExprCanBeNull(pRight)) {
 				sqlVdbeAddOp2(v, OP_IsNull, regBase + j,
@@ -733,7 +653,6 @@ codeAllEqualityTerms(Parse * pParse,	/* Parsing context */
 			}
 		}
 	}
-	*res_type = type;
 	return regBase;
 }
 
@@ -904,10 +823,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 		int iIdxCur;	/* The VDBE cursor for the index */
 		int nExtraReg = 0;	/* Number of extra registers needed */
 		int op;		/* Instruction opcode */
-		/* Types for start of range constraint. */
-		enum field_type *start_types;
-		/* Types for end of range constraint */
-		enum field_type *end_types = NULL;
 		u8 bSeekPastNull = 0;	/* True to seek past initial nulls */
 		u8 bStopAtNull = 0;	/* Add condition to terminate at NULLs */
 		int force_integer_reg = -1;  /* If non-negative: number of
@@ -994,17 +909,7 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 		 * and store the values of those terms in an array of registers
 		 * starting at regBase.
 		 */
-		regBase =
-		    codeAllEqualityTerms(pParse, pLevel, bRev, nExtraReg,
-					 &start_types);
-		if (start_types != NULL && nTop) {
-			uint32_t len = 0;
-			for (enum field_type *tmp = &start_types[nEq];
-			     *tmp != field_type_MAX; tmp++, len++);
-			uint32_t sz = len * sizeof(enum field_type);
-			end_types = sqlDbMallocRaw(db, sz);
-			memcpy(end_types, &start_types[nEq], sz);
-		}
+		regBase = codeAllEqualityTerms(pParse, pLevel, bRev, nExtraReg);
 		addrNxt = pLevel->addrNxt;
 
 		testcase(pRangeStart && (pRangeStart->eOperator & WO_LE) != 0);
@@ -1029,10 +934,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 				VdbeCoverage(v);
 			}
 
-			if (start_types) {
-				expr_cmp_update_rhs_type(pRight, nBtm,
-							 &start_types[nEq]);
-			}
 			nConstraint += nBtm;
 			testcase(pRangeStart->wtFlags & TERM_VIRTUAL);
 			if (sqlExprIsVector(pRight) == 0) {
@@ -1049,91 +950,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 		}
 		struct index_def *idx_pk = space->index[0]->def;
 		uint32_t pk_part_count = idx_pk->key_def->part_count;
-		/*
-		 * Tarantool's iterator over integer fields doesn't
-		 * tolerate floating point values. Hence, if term
-		 * is equality comparison and value of operand is
-		 * not integer, we can skip it since it always
-		 * results in false: INT a == 0.5 -> false;
-		 * It is done using OP_MustBeInt facilities.
-		 * In case term is greater comparison (a > ?), we
-		 * should notify OP_SeekGT to process truncation of
-		 * floating point value: a > 0.5 -> a >= 1;
-		 * It is done by setting P5 flag for OP_Seek*.
-		 * It is worth mentioning that we do not need
-		 * this step when it comes for less (<) comparison
-		 * of nullable field. Key is NULL in this case:
-		 * values are ordered as  NULL, ... NULL, min_value,
-		 * so to fetch min value we pass NULL to GT iterator.
-		 * The only exception is less comparison in
-		 * conjunction with ORDER BY DESC clause:
-		 * in such situation we use LE iterator and
-		 * truncated value to compare. But then
-		 * pRangeStart == NULL.
-		 * This procedure is correct for compound index:
-		 * only one comparison of less/greater type can be
-		 * used at the same time. For instance,
-		 * a < 1.5 AND b > 0.5 is handled by SeekGT using
-		 * column a and fetching column b from tuple and
-		 * OP_Le comparison.
-		 *
-		 * Note that OP_ApplyType, which is emitted before
-		 * OP_Seek** doesn't truncate floating point to
-		 * integer. That's why we need this routine.
-		 * Also, note that terms are separated by OR
-		 * predicates, so we consider term as sequence
-		 * of AND'ed predicates.
-		 */
-		size_t addrs_sz = sizeof(int) * nEq;
-		int *seek_addrs = region_alloc(&pParse->region, addrs_sz);
-		if (seek_addrs == NULL) {
-			diag_set(OutOfMemory, addrs_sz, "region", "seek_addrs");
-			pParse->is_aborted = true;
-			return 0;
-		}
-		memset(seek_addrs, 0, addrs_sz);
-		for (int i = 0; i < nEq; i++) {
-			enum field_type type = idx_def->key_def->parts[i].type;
-			if (type == FIELD_TYPE_INTEGER ||
-			    type == FIELD_TYPE_UNSIGNED) {
-				/*
-				 * OP_MustBeInt consider NULLs as
-				 * non-integer values, so firstly
-				 * check whether value is NULL or not.
-				 */
-				seek_addrs[i] = sqlVdbeAddOp1(v, OP_IsNull,
-							      regBase);
-				sqlVdbeAddOp2(v, OP_MustBeInt, regBase + i,
-					      addrNxt);
-				start_types[i] = FIELD_TYPE_SCALAR;
-				/*
-				 * We need to notify column cache
-				 * that type of value may change
-				 * so we should fetch value from
-				 * tuple again rather then copy
-				 * from register.
-				 */
-				sql_expr_type_cache_change(pParse, regBase + i,
-							   1);
-			}
-		}
-		/* Inequality constraint comes always at the end of list. */
-		part_count = idx_def->key_def->part_count;
-		if (pRangeStart != NULL) {
-			/*
-			 * nEq == 0 means that filter condition
-			 * contains only inequality.
-			 */
-			uint32_t ineq_idx = nEq == 0 ? 0 : nEq - 1;
-			assert(ineq_idx < part_count);
-			enum field_type ineq_type =
-				idx_def->key_def->parts[ineq_idx].type;
-			if (ineq_type == FIELD_TYPE_INTEGER ||
-			    ineq_type == FIELD_TYPE_UNSIGNED)
-				force_integer_reg = regBase + nEq;
-		}
-		emit_apply_type(pParse, regBase, nConstraint - bSeekPastNull,
-				start_types);
 		if (pLoop->nSkip > 0 && nConstraint == pLoop->nSkip) {
 			/* The skip-scan logic inside the call to codeAllEqualityConstraints()
 			 * above has already left the cursor sitting on the correct row,
@@ -1143,10 +959,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 			op = aStartOp[(start_constraints << 2) +
 				      (startEq << 1) + bRev];
 			assert(op != 0);
-			for (uint32_t i = 0; i < nEq; ++i) {
-				if (seek_addrs[i] != 0)
-					sqlVdbeJumpHere(v, seek_addrs[i]);
-			}
 			sqlVdbeAddOp4Int(v, op, iIdxCur, addrNxt, regBase,
 					     nConstraint);
 			/* If this is Seek* opcode, and IPK is detected in the
@@ -1186,13 +998,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 						  addrNxt);
 				VdbeCoverage(v);
 			}
-			if (end_types) {
-				expr_cmp_update_rhs_type(pRight, nTop, end_types);
-				emit_apply_type(pParse, regBase + nEq, nTop,
-						end_types);
-			} else {
-				assert(pParse->db->mallocFailed);
-			}
 			nConstraint += nTop;
 			testcase(pRangeEnd->wtFlags & TERM_VIRTUAL);
 
@@ -1206,8 +1011,6 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 			endEq = 0;
 			nConstraint++;
 		}
-		sqlDbFree(db, start_types);
-		sqlDbFree(db, end_types);
 
 		/* Top of the loop body */
 		pLevel->p2 = sqlVdbeCurrentAddr(v);
diff --git a/test/sql-tap/gh-4230-del-impl-cast-str-to-num.test.lua b/test/sql-tap/gh-4230-del-impl-cast-str-to-num.test.lua
new file mode 100755
index 0000000..ef4127e
--- /dev/null
+++ b/test/sql-tap/gh-4230-del-impl-cast-str-to-num.test.lua
@@ -0,0 +1,78 @@
+#!/usr/bin/env tarantool
+test = require("sqltester")
+test:plan(8)
+
+--
+-- Make sure that there is no implicit cast between string and
+-- number.
+--
+test:do_catchsql_test(
+    "gh-4230-1",
+    [[
+        SELECT '1' > 0;
+    ]], {
+        1, "Type mismatch: can not convert 1 to numeric"
+    })
+
+test:do_catchsql_test(
+    "gh-4230-2",
+    [[
+        SELECT 0 > '1';
+    ]], {
+        1, "Type mismatch: can not convert 1 to numeric"
+    })
+
+test:execsql([[
+        CREATE TABLE t (i INT PRIMARY KEY, d DOUBLE, n NUMBER, s STRING);
+        INSERT INTO t VALUES (1, 1.0, 1, '2'), (2, 2.0, 2.0, '2');
+    ]])
+
+test:do_catchsql_test(
+    "gh-4230-3",
+    [[
+        SELECT * from t where i > s;
+    ]], {
+        1, "Type mismatch: can not convert 2 to numeric"
+    })
+
+test:do_catchsql_test(
+    "gh-4230-4",
+    [[
+        SELECT * from t WHERE s > i;
+    ]], {
+        1, "Type mismatch: can not convert 2 to numeric"
+    })
+
+test:do_catchsql_test(
+    "gh-4230-5",
+    [[
+        SELECT * from t WHERE d > s;
+    ]], {
+        1, "Type mismatch: can not convert 2 to numeric"
+    })
+
+test:do_catchsql_test(
+    "gh-4230-6",
+    [[
+        SELECT * from t WHERE s > d;
+    ]], {
+        1, "Type mismatch: can not convert 2 to numeric"
+    })
+
+test:do_catchsql_test(
+    "gh-4230-7",
+    [[
+        SELECT * from t WHERE i = 1 and n > s;
+    ]], {
+        1, "Type mismatch: can not convert 2 to numeric"
+    })
+
+test:do_catchsql_test(
+    "gh-4230-8",
+    [[
+        SELECT * from t WHERE i = 2 and s > n;
+    ]], {
+        1, "Type mismatch: can not convert 2 to numeric"
+    })
+
+test:finish_test()
diff --git a/test/sql-tap/identifier_case.test.lua b/test/sql-tap/identifier_case.test.lua
index 2a00626..1d56ffb 100755
--- a/test/sql-tap/identifier_case.test.lua
+++ b/test/sql-tap/identifier_case.test.lua
@@ -242,11 +242,11 @@ data = {
     { 2,  [[ 'a' < 'b' collate "binary" ]], {0, {true}}},
     { 3,  [[ 'a' < 'b' collate 'binary' ]], {1, [[Syntax error at line 1 near ''binary'']]}},
     { 4,  [[ 'a' < 'b' collate "unicode" ]], {0, {true}}},
-    { 5,  [[ 5 < 'b' collate "unicode" ]], {0, {true}}},
+    { 5,  [[ 5 < 'b' collate "unicode" ]], {1, "Type mismatch: can not convert b to numeric"}},
     { 6,  [[ 5 < 'b' collate unicode ]], {1,"Collation 'UNICODE' does not exist"}},
-    { 7,  [[ 5 < 'b' collate "unicode_ci" ]], {0, {true}}},
+    { 7,  [[ 5 < 'b' collate "unicode_ci" ]], {1, "Type mismatch: can not convert b to numeric"}},
     { 8,  [[ 5 < 'b' collate NONE ]], {1, "Collation 'NONE' does not exist"}},
-    { 9,  [[ 5 < 'b' collate "none" ]], {0, {true}}},
+    { 9,  [[ 5 < 'b' collate "none" ]], {1, "Type mismatch: can not convert b to numeric"}},
 }
 
 for _, row in ipairs(data) do
diff --git a/test/sql-tap/in1.test.lua b/test/sql-tap/in1.test.lua
index 570cc17..e2f4988 100755
--- a/test/sql-tap/in1.test.lua
+++ b/test/sql-tap/in1.test.lua
@@ -637,12 +637,12 @@ test:do_test(
     "in-11.2",
     function()
         -- The '2' should be coerced into 2 because t6.b is NUMERIC
-        return test:execsql [[
+        return test:catchsql [[
             SELECT * FROM t6 WHERE b IN ('2');
         ]]
     end, {
         -- <in-11.2>
-        1, 2
+        1, "Type mismatch: can not convert 2 to numeric"
         -- </in-11.2>
     })
 
diff --git a/test/sql-tap/in4.test.lua b/test/sql-tap/in4.test.lua
index 8c69173..17a9150 100755
--- a/test/sql-tap/in4.test.lua
+++ b/test/sql-tap/in4.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(61)
+test:plan(52)
 
 --!./tcltestrunner.lua
 -- 2008 September 1
@@ -147,13 +147,13 @@ test:do_execsql_test(
         -- </in4-2.7>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "in4-2.8",
     [[
         SELECT b FROM t2 WHERE a IN ('', '0.0.0', '2') 
     ]], {
         -- <in4-2.8>
-        "two"
+        1, "Type mismatch: can not convert integer to text"
         -- </in4-2.8>
     })
 
@@ -585,98 +585,6 @@ test:do_execsql_test(
         -- </in4-4.6>
     })
 
-test:do_execsql_test(
-    "in4-4.11",
-    [[
-        CREATE TABLE t4b(a TEXT, b NUMBER, c  INT PRIMARY KEY);
-        INSERT INTO t4b VALUES('1.0',1,4);
-        SELECT c FROM t4b WHERE a=b;
-    ]], {
-        -- <in4-4.11>
-        4
-        -- </in4-4.11>
-    })
-
-test:do_execsql_test(
-    "in4-4.12",
-    [[
-        SELECT c FROM t4b WHERE b=a;
-    ]], {
-        -- <in4-4.12>
-        4
-        -- </in4-4.12>
-    })
-
-test:do_execsql_test(
-    "in4-4.13",
-    [[
-        SELECT c FROM t4b WHERE +a=b;
-    ]], {
-        -- <in4-4.13>
-        4
-        -- </in4-4.13>
-    })
-
-test:do_execsql_test(
-    "in4-4.14",
-    [[
-        SELECT c FROM t4b WHERE a=+b;
-    ]], {
-        -- <in4-4.14>
-        4
-        -- </in4-4.14>
-    })
-
-test:do_execsql_test(
-    "in4-4.15",
-    [[
-        SELECT c FROM t4b WHERE +b=a;
-    ]], {
-        -- <in4-4.15>
-        4
-        -- </in4-4.15>
-    })
-
-test:do_execsql_test(
-    "in4-4.16",
-    [[
-        SELECT c FROM t4b WHERE b=+a;
-    ]], {
-        -- <in4-4.16>
-        4
-        -- </in4-4.16>
-    })
-
-test:do_execsql_test(
-    "in4-4.17",
-    [[
-        SELECT c FROM t4b WHERE a IN (b);
-    ]], {
-        -- <in4-4.17>
-        4
-        -- </in4-4.17>
-    })
-
-test:do_execsql_test(
-    "in4-4.18",
-    [[
-        SELECT c FROM t4b WHERE b IN (a);
-    ]], {
-        -- <in4-4.18>
-        4
-        -- </in4-4.18>
-    })
-
-test:do_execsql_test(
-    "in4-4.19",
-    [[
-        SELECT c FROM t4b WHERE +b IN (a);
-    ]], {
-        -- <in4-4.19>
-        4
-        -- </in4-4.19>
-    })
-
 -- MUST_WORK_TEST
 -- Tarantool: TBI: Need to support collations. Depends on #2121
 -- test:do_execsql_test(
diff --git a/test/sql-tap/insert3.test.lua b/test/sql-tap/insert3.test.lua
index 43bb066..ff8f6de 100755
--- a/test/sql-tap/insert3.test.lua
+++ b/test/sql-tap/insert3.test.lua
@@ -59,7 +59,7 @@ test:do_execsql_test(
     [[
             CREATE TABLE log2(rowid INTEGER PRIMARY KEY AUTOINCREMENT, x TEXT UNIQUE,y INT );
             CREATE TRIGGER r2 BEFORE INSERT ON t1 FOR EACH ROW BEGIN
-              UPDATE log2 SET y=y+1 WHERE x=new.b;
+              UPDATE log2 SET y=y+1 WHERE x=CAST(new.b AS STRING);
               INSERT OR IGNORE INTO log2(x, y) VALUES(new.b,1);
             END;
             INSERT INTO t1(a, b) VALUES('hi', 453);
diff --git a/test/sql-tap/intpkey.test.lua b/test/sql-tap/intpkey.test.lua
index b6b1866..1823109 100755
--- a/test/sql-tap/intpkey.test.lua
+++ b/test/sql-tap/intpkey.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(40)
+test:plan(39)
 
 --!./tcltestrunner.lua
 -- 2001 September 15
@@ -859,43 +859,33 @@ test:do_execsql_test(
         -- </intpkey-14.2>
     })
 
-test:do_execsql_test(
-    "intpkey-14.3",
-    [[
-        SELECT * FROM t3 WHERE a>'2';
-    ]], {
-        -- <intpkey-14.3>
-        3, 3, "3"
-        -- </intpkey-14.3>
-    })
-
-test:do_execsql_test(
+test:do_catchsql_test(
     "intpkey-14.4",
     [[
         SELECT * FROM t3 WHERE a<'2';
     ]], {
         -- <intpkey-14.4>
-        1, 1, "one"
+        1, "Type mismatch: can not convert text to integer"
         -- </intpkey-14.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "intpkey-14.5",
     [[
         SELECT * FROM t3 WHERE a<c;
     ]], {
         -- <intpkey-14.5>
-        1, 1, "one"
+        1, "Type mismatch: can not convert one to numeric"
         -- </intpkey-14.5>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "intpkey-14.6",
     [[
         SELECT * FROM t3 WHERE a=c;
     ]], {
         -- <intpkey-14.6>
-        2, 2, "2", 3, 3, "3"
+        1, "Type mismatch: can not convert one to numeric"
         -- </intpkey-14.6>
     })
 
diff --git a/test/sql-tap/join.test.lua b/test/sql-tap/join.test.lua
index 840b780..792302a 100755
--- a/test/sql-tap/join.test.lua
+++ b/test/sql-tap/join.test.lua
@@ -1028,23 +1028,23 @@ test:do_test(
         -- </join-11.8>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "join-11.9",
     [[
         SELECT * FROM t1 NATURAL JOIN t2 
     ]], {
         -- <join-11.9>
-        "one", "1", "two", "2"
+        1, "Type mismatch: can not convert integer to text"
         -- </join-11.9>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "join-11.10",
     [[
         SELECT * FROM t2 NATURAL JOIN t1 
     ]], {
         -- <join-11.10>
-        1, "one", 2, "two"
+        1, "Type mismatch: can not convert 1 to numeric"
         -- </join-11.10>
     })
 
diff --git a/test/sql-tap/misc1.test.lua b/test/sql-tap/misc1.test.lua
index 32f38cc..1cf6bd9 100755
--- a/test/sql-tap/misc1.test.lua
+++ b/test/sql-tap/misc1.test.lua
@@ -88,7 +88,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "misc1-1.4",
     [[
-        SELECT x75 FROM manycol WHERE x50=350
+        SELECT x75 FROM manycol WHERE x50='350'
     ]], {
         -- <misc1-1.4>
         "375"
@@ -98,7 +98,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "misc1-1.5",
     [[
-        SELECT x50 FROM manycol WHERE x99=599
+        SELECT x50 FROM manycol WHERE x99='599'
     ]], {
         -- <misc1-1.5>
         "550"
@@ -109,7 +109,7 @@ test:do_test(
     "misc1-1.6",
     function()
         test:execsql("CREATE INDEX manycol_idx1 ON manycol(x99)")
-        return test:execsql("SELECT x50 FROM manycol WHERE x99=899")
+        return test:execsql("SELECT x50 FROM manycol WHERE x99='899'")
     end, {
         -- <misc1-1.6>
         "850"
@@ -129,7 +129,7 @@ test:do_execsql_test(
 test:do_test(
     "misc1-1.8",
     function()
-        test:execsql("DELETE FROM manycol WHERE x98=1234")
+        test:execsql("DELETE FROM manycol WHERE x98='1234'")
         return test:execsql("SELECT count(*) FROM manycol")
     end, {
         -- <misc1-1.8>
@@ -140,7 +140,7 @@ test:do_test(
 test:do_test(
     "misc1-1.9",
     function()
-        test:execsql("DELETE FROM manycol WHERE x98=998")
+        test:execsql("DELETE FROM manycol WHERE x98='998'")
         return test:execsql("SELECT count(*) FROM manycol")
     end, {
         -- <misc1-1.9>
@@ -151,7 +151,7 @@ test:do_test(
 test:do_test(
     "misc1-1.10",
     function()
-        test:execsql("DELETE FROM manycol WHERE x99=500")
+        test:execsql("DELETE FROM manycol WHERE x99='500'")
         return test:execsql("SELECT count(*) FROM manycol")
     end, {
         -- <misc1-1.10>
@@ -162,7 +162,7 @@ test:do_test(
 test:do_test(
     "misc1-1.11",
     function()
-        test:execsql("DELETE FROM manycol WHERE x99=599")
+        test:execsql("DELETE FROM manycol WHERE x99='599'")
         return test:execsql("SELECT count(*) FROM manycol")
     end, {
         -- <misc1-1.11>
@@ -479,9 +479,9 @@ local where = ""
 test:do_test(
     "misc1-10.1",
     function()
-        where = "WHERE x0>=0"
+        where = "WHERE x0>='0'"
         for i = 1, 99, 1 do
-            where = where .. " AND x"..i.."<>0"
+            where = where .. " AND x"..i.."<>'0'"
         end
         return test:catchsql("SELECT count(*) FROM manycol "..where.."")
     end, {
@@ -496,7 +496,7 @@ test:do_test(
 test:do_test(
     "misc1-10.3",
     function()
-        where = string.gsub(where,"x0>=0", "x0=0")
+        where = string.gsub(where,"x0>='0'", "x0='0'")
         return test:catchsql("DELETE FROM manycol "..where.."")
     end, {
         -- <misc1-10.3>
@@ -520,7 +520,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "misc1-10.6",
     [[
-        SELECT x1 FROM manycol WHERE x0=100
+        SELECT x1 FROM manycol WHERE x0='100'
     ]], {
         -- <misc1-10.6>
         "101"
@@ -530,7 +530,7 @@ test:do_execsql_test(
 test:do_test(
     "misc1-10.7",
     function()
-        where = string.gsub(where, "x0=0", "x0=100")
+        where = string.gsub(where, "x0='0'", "x0='100'")
         return test:catchsql("UPDATE manycol SET x1=x1+1 "..where.."")
     end, {
         -- <misc1-10.7>
@@ -541,7 +541,7 @@ test:do_test(
 test:do_execsql_test(
     "misc1-10.8",
     [[
-        SELECT x1 FROM manycol WHERE x0=100
+        SELECT x1 FROM manycol WHERE x0='100'
     ]], {
         -- <misc1-10.8>
         "102"
@@ -563,7 +563,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "misc1-10.10",
     [[
-        SELECT x1 FROM manycol WHERE x0=100
+        SELECT x1 FROM manycol WHERE x0='100'
     ]], {
         -- <misc1-10.10>
         "103"
@@ -619,13 +619,13 @@ test:do_execsql_test(
         -- </misc1-12.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "misc1-12.2",
     [[
         SELECT '0'==0.0
     ]], {
         -- <misc1-12.2>
-        true
+        1, "Type mismatch: can not convert 0 to numeric"
         -- </misc1-12.2>
     })
 
diff --git a/test/sql-tap/select1.test.lua b/test/sql-tap/select1.test.lua
index fbebfab..cb4bece 100755
--- a/test/sql-tap/select1.test.lua
+++ b/test/sql-tap/select1.test.lua
@@ -1912,7 +1912,7 @@ test:do_execsql_test(
 test:do_execsql_test(
         "select1-12.7",
         [[
-            SELECT * FROM t3 WHERE a=(SELECT 1);
+            SELECT * FROM t3 WHERE a=(SELECT '1');
         ]], {
             -- <select1-12.7>
             0, "1", "2"
@@ -1922,7 +1922,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "select1-12.8",
     [[
-        SELECT * FROM t3 WHERE a=(SELECT 2);
+        SELECT * FROM t3 WHERE a=(SELECT '2');
     ]], {
         -- <select1-12.8>
 
diff --git a/test/sql-tap/select7.test.lua b/test/sql-tap/select7.test.lua
index fec5d7a..a5c4e41 100755
--- a/test/sql-tap/select7.test.lua
+++ b/test/sql-tap/select7.test.lua
@@ -256,7 +256,7 @@ test:do_execsql_test(
         DROP TABLE IF EXISTS t5;
         CREATE TABLE t5(a TEXT primary key, b INT);
         INSERT INTO t5 VALUES(123, 456);
-        SELECT typeof(a), a FROM t5 GROUP BY a HAVING a<b;
+        SELECT typeof(a), a FROM t5 GROUP BY a HAVING CAST(a AS INTEGER)<b;
     ]], {
         -- <select7-7.7>
         "string", "123"
diff --git a/test/sql-tap/subquery.test.lua b/test/sql-tap/subquery.test.lua
index 15c4c82..e3d2cee 100755
--- a/test/sql-tap/subquery.test.lua
+++ b/test/sql-tap/subquery.test.lua
@@ -284,13 +284,13 @@ test:do_execsql_test(
         -- </subquery-2.3.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "subquery-2.3.2",
     [[
         SELECT a IN (10.0, 20) FROM t3;
     ]], {
         -- <subquery-2.3.2>
-        false
+        1, "Type mismatch: can not convert text to real"
         -- </subquery-2.3.2>
     })
 
diff --git a/test/sql-tap/tkt-9a8b09f8e6.test.lua b/test/sql-tap/tkt-9a8b09f8e6.test.lua
index cb5348a..2a18b17 100755
--- a/test/sql-tap/tkt-9a8b09f8e6.test.lua
+++ b/test/sql-tap/tkt-9a8b09f8e6.test.lua
@@ -83,23 +83,23 @@ test:do_execsql_test(
         -- </1.5>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     2.1,
     [[
         SELECT x FROM t1 WHERE x IN (1);
     ]], {
         -- <2.1>
-        "1"
+        1,"Type mismatch: can not convert 1 to numeric"
         -- </2.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     2.2,
     [[
         SELECT x FROM t1 WHERE x IN (1.0);
     ]], {
         -- <2.2>
-        "1"
+        1,"Type mismatch: can not convert 1 to numeric"
         -- </2.2>
     })
 
@@ -123,23 +123,23 @@ test:do_execsql_test(
         -- </2.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     2.5,
     [[
         SELECT x FROM t1 WHERE 1 IN (x);
     ]], {
         -- <2.5>
-        "1"
+        1,"Type mismatch: can not convert 1 to numeric"
         -- </2.5>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     2.6,
     [[
         SELECT x FROM t1 WHERE 1.0 IN (x);
     ]], {
         -- <2.6>
-        "1"
+        1,"Type mismatch: can not convert 1 to numeric"
         -- </2.6>
     })
 
@@ -183,23 +183,23 @@ test:do_execsql_test(
         -- </3.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     3.3,
     [[
         SELECT x FROM t2 WHERE x IN ('1');
     ]], {
         -- <3.3>
-        1
+        1, "Type mismatch: can not convert integer to text"
         -- </3.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     3.4,
     [[
         SELECT x FROM t2 WHERE x IN ('1');
     ]], {
         -- <3.4>
-        1
+        1, "Type mismatch: can not convert integer to text"
         -- </3.4>
     })
 
@@ -223,23 +223,23 @@ test:do_execsql_test(
         -- </3.6>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     3.7,
     [[
         SELECT x FROM t2 WHERE '1' IN (x);
     ]], {
         -- <3.7>
-        1
+        1, "Type mismatch: can not convert integer to text"
         -- </3.7>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     3.8,
     [[
         SELECT x FROM t2 WHERE '1' IN (x);
     ]], {
         -- <3.8>
-        1
+        1, "Type mismatch: can not convert integer to text"
         -- </3.8>
     })
 
@@ -263,23 +263,23 @@ test:do_execsql_test(
         -- </4.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     4.3,
     [[
         SELECT x FROM t3 WHERE x IN ('1');
     ]], {
         -- <4.3>
-        1.0
+        1, "Type mismatch: can not convert number to text"
         -- </4.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     4.4,
     [[
         SELECT x FROM t3 WHERE x IN ('1.0');
     ]], {
         -- <4.4>
-        1.0
+        1, "Type mismatch: can not convert number to text"
         -- </4.4>
     })
 
@@ -303,23 +303,23 @@ test:do_execsql_test(
         -- </4.6>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     4.7,
     [[
         SELECT x FROM t3 WHERE '1' IN (x);
     ]], {
         -- <4.7>
-        1
+        1, "Type mismatch: can not convert number to text"
         -- </4.7>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     4.8,
     [[
         SELECT x FROM t3 WHERE '1.0' IN (x);
     ]], {
         -- <4.8>
-        1
+        1, "Type mismatch: can not convert number to text"
         -- </4.8>
     })
 
@@ -343,23 +343,23 @@ test:do_execsql_test(
         -- </5.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     5.3,
     [[
         SELECT x FROM t4 WHERE x IN ('1');
     ]], {
         -- <5.3>
-        
+        1, "Type mismatch: can not convert number to text"
         -- </5.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     5.4,
     [[
         SELECT x FROM t4 WHERE x IN ('1.0');
     ]], {
         -- <5.4>
-        
+        1, "Type mismatch: can not convert number to text"
         -- </5.4>
     })
 
@@ -373,13 +373,13 @@ test:do_execsql_test(
         -- </5.5>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     5.6,
     [[
         SELECT x FROM t4 WHERE x IN ('1.11');
     ]], {
         -- <5.6>
-        1.11
+        1, "Type mismatch: can not convert number to text"
         -- </5.6>
     })
 
@@ -403,23 +403,23 @@ test:do_execsql_test(
         -- </5.8>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     5.9,
     [[
         SELECT x FROM t4 WHERE '1' IN (x);
     ]], {
         -- <5.9>
-        
+        1, "Type mismatch: can not convert number to text"
         -- </5.9>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     5.10,
     [[
         SELECT x FROM t4 WHERE '1.0' IN (x);
     ]], {
         -- <5.10>
-        
+        1, "Type mismatch: can not convert number to text"
         -- </5.10>
     })
 
@@ -433,13 +433,13 @@ test:do_execsql_test(
         -- </5.11>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     5.12,
     [[
         SELECT x FROM t4 WHERE '1.11' IN (x);
     ]], {
         -- <5.12>
-        1.11
+        1, "Type mismatch: can not convert number to text"
         -- </5.12>
     })
 
@@ -463,23 +463,23 @@ test:do_execsql_test(
         -- </6.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     6.3,
     [[
         SELECT x, y FROM t5 WHERE x IN ('1');
     ]], {
         -- <6.3>
-        1, "one", 1, "two", 1, "three", 1.0, "four"
+        1, "Type mismatch: can not convert 1 to numeric"
         -- </6.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     6.4,
     [[
         SELECT x, y FROM t5 WHERE x IN ('1.0');
     ]], {
         -- <6.4>
-        1, "one", 1, "two", 1, "three", 1.0, "four"
+        1, "Type mismatch: can not convert 1.0 to numeric"
         -- </6.4>
     })
 
@@ -503,23 +503,23 @@ test:do_execsql_test(
         -- </6.6>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     6.7,
     [[
         SELECT x, y FROM t5 WHERE '1' IN (x);
     ]], {
         -- <6.7>
-        1, "one", 1, "two", 1, "three", 1.0, "four"
+        1, "Type mismatch: can not convert 1 to numeric"
         -- </6.7>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     6.8,
     [[
         SELECT x, y FROM t5 WHERE '1.0' IN (x);
     ]], {
         -- <6.8>
-        1, "one", 1, "two", 1, "three", 1, "four"
+        1, "Type mismatch: can not convert 1.0 to numeric"
         -- </6.8>
     })
 
diff --git a/test/sql-tap/tkt-f973c7ac31.test.lua b/test/sql-tap/tkt-f973c7ac31.test.lua
index 82bdb52..5239a77 100755
--- a/test/sql-tap/tkt-f973c7ac31.test.lua
+++ b/test/sql-tap/tkt-f973c7ac31.test.lua
@@ -36,12 +36,12 @@ local sqls = {
 
 for tn, sql in ipairs(sqls) do
     test:execsql(sql)
-    test:do_execsql_test(
+    test:do_catchsql_test(
         "tkt-f973c7ac3-1."..tn..".1",
         [[
             SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND c2<='2' ORDER BY c2 DESC 
         ]], {
-            
+            1, "/Type mismatch: can not convert/"
         })
 
     test:do_execsql_test(
@@ -52,36 +52,36 @@ for tn, sql in ipairs(sqls) do
             5, 5, 5, 4
         })
 
-    test:do_execsql_test(
+    test:do_catchsql_test(
         "tkt-f973c7ac3-1."..tn..".3",
         [[
             SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND c2<='5' ORDER BY c2 DESC 
         ]], {
-            5, 5, 5, 4
+            1, "/Type mismatch: can not convert/"
         })
 
-    test:do_execsql_test(
+    test:do_catchsql_test(
         "tkt-f973c7ac3-1."..tn..".4",
         [[
             SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>'0' AND c2<=5 ORDER BY c2 DESC 
         ]], {
-            5, 5, 5, 4
+            1, "/Type mismatch: can not convert/"
         })
 
-    test:do_execsql_test(
+    test:do_catchsql_test(
         "tkt-f973c7ac3-1."..tn..".5",
         [[
             SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>'0' AND c2<='5' ORDER BY c2 DESC 
         ]], {
-            5, 5, 5, 4
+            1, "/Type mismatch: can not convert/"
         })
 
-    test:do_execsql_test(
+    test:do_catchsql_test(
         "tkt-f973c7ac3-1."..tn..".6",
         [[
             SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND c2<='2' ORDER BY c2 ASC 
         ]], {
-            
+            1, "/Type mismatch: can not convert/"
         })
 
     test:do_execsql_test(
@@ -92,28 +92,28 @@ for tn, sql in ipairs(sqls) do
             5, 4, 5, 5
         })
 
-    test:do_execsql_test(
+    test:do_catchsql_test(
         "tkt-f973c7ac3-1."..tn..".8",
         [[
             SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND c2<='5' ORDER BY c2 ASC 
         ]], {
-            5, 4, 5, 5
+            1, "/Type mismatch: can not convert/"
         })
 
-    test:do_execsql_test(
+    test:do_catchsql_test(
         "tkt-f973c7ac3-1."..tn..".9",
         [[
             SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>'0' AND c2<=5 ORDER BY c2 ASC 
         ]], {
-            5, 4, 5, 5
+            1, "/Type mismatch: can not convert/"
         })
 
-    test:do_execsql_test(
+    test:do_catchsql_test(
         "tkt-f973c7ac3-1."..tn..".10",
         [[
             SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>'0' AND c2<='5' ORDER BY c2 ASC 
         ]], {
-            5, 4, 5, 5
+            1, "/Type mismatch: can not convert/"
         })
 
 end
diff --git a/test/sql-tap/tkt-fc7bd6358f.test.lua b/test/sql-tap/tkt-fc7bd6358f.test.lua
index fe5d620..f77e4be 100755
--- a/test/sql-tap/tkt-fc7bd6358f.test.lua
+++ b/test/sql-tap/tkt-fc7bd6358f.test.lua
@@ -78,17 +78,17 @@ for a, from in ipairs(froms) do
         test:do_test(
             string.format("tkt-fc7bd6358f.110.%s.%s.1", a, b),
             function()
-                return test:execsql(string.format("SELECT t1.textid, i.intid, t2.textid %s %s", from, where))
+                return test:catchsql(string.format("SELECT t1.textid, i.intid, t2.textid %s %s", from, where))
             end, {
-                "12", 12, "12", "34", 34, "34"
+                1, "Type mismatch: can not convert integer to text"
             })
 
         test:do_test(
             string.format("tkt-fc7bd6358f.110.%s.%s.2", a, b),
             function()
-                return test:execsql(string.format("SELECT t1.textid, i.intid, t2.textid %s %s", from, where))
+                return test:catchsql(string.format("SELECT t1.textid, i.intid, t2.textid %s %s", from, where))
             end, {
-                "12", 12, "12", "34", 34, "34"
+                1, "Type mismatch: can not convert integer to text"
             })
 
     end
diff --git a/test/sql-tap/tkt3493.test.lua b/test/sql-tap/tkt3493.test.lua
index 7ceec47..1d31c0c 100755
--- a/test/sql-tap/tkt3493.test.lua
+++ b/test/sql-tap/tkt3493.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(26)
+test:plan(25)
 
 --!./tcltestrunner.lua
 -- 2008 October 13
@@ -45,7 +45,7 @@ test:do_execsql_test(
     [[
         SELECT 
           CASE 
-             WHEN B.val = 1 THEN 'XYZ' 
+             WHEN B.val = '1' THEN 'XYZ'
              ELSE A.val 
           END AS Col1
         FROM B  
@@ -63,7 +63,7 @@ test:do_execsql_test(
     [[
         SELECT DISTINCT
           CASE 
-             WHEN B.val = 1 THEN 'XYZ' 
+             WHEN B.val = '1' THEN 'XYZ'
              ELSE A.val 
           END AS Col1
         FROM B  
@@ -79,7 +79,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-1.4",
     [[
-        SELECT b.val, CASE WHEN b.val = 1 THEN 'xyz' ELSE b.val END AS col1 FROM b;
+        SELECT b.val, CASE WHEN b.val = '1' THEN 'xyz' ELSE b.val END AS col1 FROM b;
     ]], {
         -- <tkt3493-1.4>
         "1", "xyz", "2", "2"
@@ -91,7 +91,7 @@ test:do_execsql_test(
     [[
         SELECT DISTINCT 
           b.val, 
-          CASE WHEN b.val = 1 THEN 'xyz' ELSE b.val END AS col1 
+          CASE WHEN b.val = '1' THEN 'xyz' ELSE b.val END AS col1
         FROM b;
     ]], {
         -- <tkt3493-1.5>
@@ -126,7 +126,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.2.1",
     [[
-        SELECT a=123 FROM t1 GROUP BY a 
+        SELECT a='123' FROM t1 GROUP BY a 
     ]], {
         -- <tkt3493-2.2.1>
         true
@@ -134,16 +134,6 @@ test:do_execsql_test(
     })
 
 test:do_execsql_test(
-    "tkt3493-2.2.2",
-    [[
-        SELECT a=123 FROM t1 
-    ]], {
-        -- <tkt3493-2.2.2>
-        true
-        -- </tkt3493-2.2.2>
-    })
-
-test:do_execsql_test(
     "tkt3493-2.2.3",
     [[
         SELECT a='123' FROM t1 
@@ -156,7 +146,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.2.4",
     [[
-        SELECT count(*), a=123 FROM t1 
+        SELECT count(*), a='123' FROM t1 
     ]], {
         -- <tkt3493-2.2.4>
         1, true
@@ -166,7 +156,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.2.5",
     [[
-        SELECT count(*), +a=123 FROM t1 
+        SELECT count(*), +a='123' FROM t1 
     ]], {
         -- <tkt3493-2.2.5>
         1, true
@@ -176,7 +166,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.3.3",
     [[
-        SELECT b='456' FROM t1 GROUP BY a 
+        SELECT b = 456 FROM t1 GROUP BY a
     ]], {
         -- <tkt3493-2.3.3>
         true
@@ -186,7 +176,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.3.1",
     [[
-        SELECT b='456' FROM t1 GROUP BY b 
+        SELECT b = 456 FROM t1 GROUP BY b
     ]], {
         -- <tkt3493-2.3.1>
         true
@@ -196,7 +186,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.3.2",
     [[
-        SELECT b='456' FROM t1 
+        SELECT b = 456 FROM t1
     ]], {
         -- <tkt3493-2.3.2>
         true
@@ -206,7 +196,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.4.1",
     [[
-        SELECT typeof(a), a FROM t1 GROUP BY a HAVING a=123 
+        SELECT typeof(a), a FROM t1 GROUP BY a HAVING a='123'
     ]], {
         -- <tkt3493-2.4.1>
         "string", "123"
@@ -216,7 +206,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.4.2",
     [[
-        SELECT typeof(a), a FROM t1 GROUP BY b HAVING a=123 
+        SELECT typeof(a), a FROM t1 GROUP BY b HAVING a='123'
     ]], {
         -- <tkt3493-2.4.2>
         "string", "123"
@@ -226,7 +216,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.5.1",
     [[
-        SELECT typeof(b), b FROM t1 GROUP BY a HAVING b='456' 
+        SELECT typeof(b), b FROM t1 GROUP BY a HAVING b=456
     ]], {
         -- <tkt3493-2.5.1>
         "integer", 456
@@ -236,7 +226,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.5.2",
     [[
-        SELECT typeof(b), b FROM t1 GROUP BY b HAVING b='456' 
+        SELECT typeof(b), b FROM t1 GROUP BY b HAVING b=456
     ]], {
         -- <tkt3493-2.5.2>
         "integer", 456
diff --git a/test/sql-tap/transitive1.test.lua b/test/sql-tap/transitive1.test.lua
index e960565..cc7e066 100755
--- a/test/sql-tap/transitive1.test.lua
+++ b/test/sql-tap/transitive1.test.lua
@@ -63,7 +63,7 @@ test:do_execsql_test(
         INSERT INTO t2 VALUES(2, 20,20,'20');
         INSERT INTO t2 VALUES(3, 3,3,'3');
 
-        SELECT a,b,c FROM t2 WHERE a=b AND c=b AND c=20;
+        SELECT a,b,c FROM t2 WHERE a=b AND c=CAST(b AS STRING) AND c='20';
     ]], {
         -- <transitive1-200>
         20, 20, "20"
@@ -73,7 +73,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "transitive1-210",
     [[
-        SELECT a,b,c FROM t2 WHERE a=b AND c=b AND c>='20' ORDER BY +a;
+        SELECT a,b,c FROM t2 WHERE a=b AND c=CAST(b AS STRING) AND c>='20' ORDER BY +a;
     ]], {
         -- <transitive1-210>
         3, 3, "3", 20, 20, "20"
@@ -83,7 +83,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "transitive1-220",
     [[
-        SELECT a,b,c FROM t2 WHERE a=b AND c=b AND c<='20' ORDER BY +a;
+        SELECT a,b,c FROM t2 WHERE a=b AND c=CAST(b AS STRING) AND c<='20' ORDER BY +a;
     ]], {
         -- <transitive1-220>
         20, 20, "20", 100, 100, "100"
@@ -338,7 +338,7 @@ test:do_execsql_test(
                    ON tvshow.idshow = episode.idshow
                  LEFT JOIN seasons
                         ON seasons.idshow = episode.idshow
-                           AND seasons.season = episode.c12
+                           AND seasons.season = CAST(episode.c12 AS INTEGER)
                  JOIN path
                    ON files.idpath = path.idpath
                  LEFT JOIN bookmark
@@ -378,7 +378,7 @@ test:do_execsql_test(
         FROM episodeview
             JOIN tvshowview ON tvshowview.idShow = episodeview.idShow
             JOIN seasons ON (seasons.idShow = tvshowview.idShow
-                             AND seasons.season = episodeview.c12)
+                             AND seasons.season = CAST(episodeview.c12 AS INTEGER))
             JOIN files ON files.idFile = episodeview.idFile
             JOIN tvshowlinkpath ON tvshowlinkpath.idShow = tvshowview.idShow
             JOIN path ON path.idPath = tvshowlinkpath.idPath
@@ -402,7 +402,7 @@ test:do_execsql_test(
     [[
         CREATE TABLE x(i INTEGER PRIMARY KEY, y TEXT);
         INSERT INTO x VALUES(10, '10');
-        SELECT * FROM x WHERE x.y>='1' AND x.y<'2' AND x.i=x.y;
+        SELECT * FROM x WHERE x.y>='1' AND x.y<'2' AND CAST(x.i AS STRING)=x.y;
     ]], {
         -- <transitive1-500>
         10, "10"
@@ -430,7 +430,7 @@ test:do_execsql_test(
     [[
         CREATE TABLE t3(i INTEGER PRIMARY KEY, t TEXT);
         INSERT INTO t3 VALUES(10, '10');
-        SELECT * FROM t3 WHERE i=t AND t = '10 ';
+        SELECT * FROM t3 WHERE CAST(i AS STRING)=t AND t = '10 ';
     ]], {
         -- <transitive1-520>
 
@@ -443,7 +443,7 @@ test:do_execsql_test(
         CREATE TABLE u1(x TEXT PRIMARY KEY, y INTEGER, z TEXT);
         CREATE INDEX i1 ON u1(x);
         INSERT INTO u1 VALUES('00013', 13, '013');
-        SELECT * FROM u1 WHERE x=y AND y=z AND z='013';
+        SELECT * FROM u1 WHERE CAST(x AS INTEGER)=y AND y=CAST(z AS INTEGER) AND z='013';
     ]], {
         -- <transitive1-530>
         "00013",13,"013"
diff --git a/test/sql-tap/where2.test.lua b/test/sql-tap/where2.test.lua
index f267be8..7348a85 100755
--- a/test/sql-tap/where2.test.lua
+++ b/test/sql-tap/where2.test.lua
@@ -4,7 +4,7 @@ yaml = require("yaml")
 fio = require("fio")
 
 ffi = require("ffi")
-test:plan(74)
+test:plan(62)
 
 ffi.cdef[[
        int dup(int oldfd);
@@ -622,181 +622,12 @@ test:do_test(
         -- </where2-6.6>
     })
 
--- if X(356, "X!cmd", [=[["expr","[permutation] != \"no_optimization\""]]=])
--- then
-    -- Ticket #2249.  Make sure the OR optimization is not attempted if
-    -- comparisons between columns of different affinities are needed.
-    --
-    test:do_test(
-        "where2-6.7",
-        function()
-            test:execsql [[
-                CREATE TABLE t2249a(a TEXT PRIMARY KEY, x VARCHAR(100));
-                CREATE TABLE t2249b(b INTEGER PRIMARY KEY);
-                INSERT INTO t2249a(a) VALUES('0123');
-                INSERT INTO t2249b VALUES(123);
-            ]]
-            return queryplan([[
-    -- Because a is type TEXT and b is type INTEGER, both a and b
-    -- will attempt to convert to NUMERIC before the comparison.
-    -- They will thus compare equal.
-    --
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=b;
-  ]])
-        end, {
-            -- <where2-6.7>
-            123, '0123', "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.7>
-        })
-
-    test:do_test(
-        "where2-6.9",
-        function()
-            return queryplan([[
-    -- The + operator doesn't affect RHS.
-    --
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=+b;
-  ]])
-        end, {
-            -- <where2-6.9>
-            123, "0123", "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.9>
-        })
-
-    test:do_test(
-        "where2-6.9.2",
-        function()
-            -- The same thing but with the expression flipped around.
-            return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +b=a
-  ]])
-        end, {
-            -- <where2-6.9.2>
-            123, "0123","nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.9.2>
-        })
-
-    test:do_test(
-        "where2-6.10",
-        function()
-            return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +a=+b;
-  ]])
-        end, {
-            -- <where2-6.10>
-            123, "0123", "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.10>
-        })
-
-    test:do_test(
-        "where2-6.11",
-        function()
-            -- This will not attempt the OR optimization because of the a=b
-            -- comparison.
-            return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=b OR a='hello';
-  ]])
-        end, {
-            -- <where2-6.11>
-            123, '0123', "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.11>
-        })
-
-    test:do_test(
-        "where2-6.11.2",
-        function()
-            -- Permutations of the expression terms.
-            return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE b=a OR a='hello';
-  ]])
-        end, {
-            -- <where2-6.11.2>
-            123, '0123', "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.11.2>
-        })
-
-    test:do_test(
-        "where2-6.11.3",
-        function()
-            -- Permutations of the expression terms.
-            return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE 'hello'=a OR b=a;
-  ]])
-        end, {
-            -- <where2-6.11.3>
-            123, '0123', "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.11.3>
-        })
-
-    test:do_test(
-        "where2-6.11.4",
-        function()
-            -- Permutations of the expression terms.
-            return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR b=a;
-  ]])
-        end, {
-            -- <where2-6.11.4>
-            123, '0123', "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.11.4>
-        })
-
-    -- These tests are not run if subquery support is not included in the
-    -- build. This is because these tests test the "a = 1 OR a = 2" to
-    -- "a IN (1, 2)" optimisation transformation, which is not enabled if
-    -- subqueries and the IN operator is not available.
-    --
-    test:do_test(
-        "where2-6.12",
-        function()
-            return queryplan([[
-      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=+b OR a='hello';
-    ]])
-        end, {
-            -- <where2-6.12>
-            123, "0123", "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.12>
-        })
-
-    test:do_test(
-        "where2-6.12.2",
-        function()
-            return queryplan([[
-      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR +b=a;
-    ]])
-        end, {
-            -- <where2-6.12.2>
-            123, "0123", "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.12.2>
-        })
-
-    test:do_test(
-        "where2-6.12.3",
-        function()
-            return queryplan([[
-      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +b=a OR a='hello';
-    ]])
-        end, {
-            -- <where2-6.12.3>
-            123, "0123", "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.12.3>
-        })
-
-    test:do_test(
-        "where2-6.13",
-        function()
-            -- The addition of +a on the second term disabled the OR optimization.
-            -- But we should still get the same empty-set result as in where2-6.9.
-            return queryplan([[
-      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=+b OR +a='hello';
-    ]])
-        end, {
-            -- <where2-6.13>
-            123, "0123", "nosort", "T2249B", "*", "T2249A", "*"
-            -- </where2-6.13>
-        })
-
-
+    test:execsql [[
+        CREATE TABLE t2249a(a TEXT PRIMARY KEY, x VARCHAR(100));
+        CREATE TABLE t2249b(b INTEGER PRIMARY KEY);
+        INSERT INTO t2249a(a) VALUES('0123');
+        INSERT INTO t2249b VALUES(123);
+    ]]
 
     -- Variations on the order of terms in a WHERE clause in order
     -- to make sure the OR optimizer can recognize them all.
diff --git a/test/sql-tap/where5.test.lua b/test/sql-tap/where5.test.lua
index 7492015..fc532c5 100755
--- a/test/sql-tap/where5.test.lua
+++ b/test/sql-tap/where5.test.lua
@@ -34,7 +34,7 @@ test:do_test("where5-1.0", function()
         INSERT INTO t3 SELECT * FROM t1;
     ]]
     return test:execsql [[
-        SELECT * FROM t1 WHERE x<0
+        SELECT * FROM t1 WHERE CAST(x AS INTEGER)<0
     ]]
 end, {
     -- <where5-1.0>
@@ -43,7 +43,7 @@ end, {
 })
 
 test:do_execsql_test("where5-1.1", [[
-    SELECT * FROM t1 WHERE x<=0
+    SELECT * FROM t1 WHERE CAST(x AS INTEGER)<=0
 ]], {
     -- <where5-1.1>
     '-1', '0'
@@ -51,7 +51,7 @@ test:do_execsql_test("where5-1.1", [[
 })
 
 test:do_execsql_test("where5-1.2", [[
-    SELECT * FROM t1 WHERE x=0
+    SELECT * FROM t1 WHERE CAST(x AS INTEGER)=0
 ]], {
     -- <where5-1.2>
     '0'
@@ -59,7 +59,7 @@ test:do_execsql_test("where5-1.2", [[
 })
 
 test:do_execsql_test("where5-1.3", [[
-    SELECT * FROM t1 WHERE x>=0
+    SELECT * FROM t1 WHERE CAST(x AS INTEGER)>=0
 ]], {
     -- <where5-1.3>
     '0', '1'
@@ -67,7 +67,7 @@ test:do_execsql_test("where5-1.3", [[
 })
 
 test:do_execsql_test("where5-1.4", [[
-    SELECT * FROM t1 WHERE x>0
+    SELECT * FROM t1 WHERE CAST(x AS INTEGER)>0
 ]], {
     -- <where5-1.4>
     '1'
@@ -75,7 +75,7 @@ test:do_execsql_test("where5-1.4", [[
 })
 
 test:do_execsql_test("where5-1.5", [[
-    SELECT * FROM t1 WHERE x<>0
+    SELECT * FROM t1 WHERE CAST(x AS INTEGER)<>0
 ]], {
     -- <where5-1.5>
     '-1', '1'
diff --git a/test/sql-tap/whereB.test.lua b/test/sql-tap/whereB.test.lua
index d98645f..b9ff361 100755
--- a/test/sql-tap/whereB.test.lua
+++ b/test/sql-tap/whereB.test.lua
@@ -27,8 +27,7 @@ test:plan(63)
 -- These values are not equal and because neither affinity is NUMERIC
 -- no type conversion occurs.
 --
-test:do_execsql_test(
-    "whereB-1.1",
+test:execsql(
     [[
         CREATE TABLE t1(x  INT primary key,y INT );    -- affinity of t1.y is NONE
         INSERT INTO t1 VALUES(1,99);
@@ -36,49 +35,54 @@ test:do_execsql_test(
         CREATE TABLE t2(a  INT primary key, b TEXT);  -- affinity of t2.b is TEXT
         CREATE INDEX t2b ON t2(b);
         INSERT INTO t2 VALUES(2,'99');
+    ]]
+)
 
+test:do_catchsql_test(
+    "whereB-1.1",
+    [[
         SELECT x, a, y=b FROM t1, t2 ORDER BY +x, +a;
     ]],
     {
     -- <whereB-1.1>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-1.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-1.2",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE y=b;
     ]],
     {
     -- <whereB-1.2>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-1.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-1.3",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-1.3>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-1.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-1.4",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
     ]],
     {
     -- <whereB-1.4>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-1.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-1.100",
     [[
         DROP INDEX t2b ON t2;
@@ -86,29 +90,29 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-1.100>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-1.100>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-1.101",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-1.101>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-1.101>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-1.102",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
     ]],
     {
     -- <whereB-1.102>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-1.102>
     })
 
@@ -312,8 +316,7 @@ test:do_execsql_test(
 -- Because t2.b has a numeric affinity, type conversion should occur
 -- and the two fields should be equal.
 --
-test:do_execsql_test(
-    "whereB-4.1",
+test:execsql(
     [[
         DROP TABLE IF EXISTS t1;
         DROP TABLE IF EXISTS t2;
@@ -324,38 +327,44 @@ test:do_execsql_test(
         CREATE TABLE t2(a  INT primary key, b NUMBER);  -- affinity of t2.b is NUMERIC
         CREATE INDEX t2b ON t2(b);
         INSERT INTO t2 VALUES(2,99);
+    ]]
+)
 
+
+test:do_catchsql_test(
+    "whereB-4.1",
+    [[
         SELECT x, a, y=b FROM t1, t2;
     ]],
     {
     -- <whereB-4.1>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-4.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-4.2",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE y=b;
     ]],
     {
     -- <whereB-4.2>
-    1, 2, true
+    1, "Type mismatch: can not convert number to text"
     -- </whereB-4.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-4.3",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-4.3>
-    1, 2, true
+    1, "Type mismatch: can not convert number to text"
     -- </whereB-4.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-4.4",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -364,11 +373,11 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-4.4>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-4.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-4.100",
     [[
         DROP INDEX t2b ON t2;
@@ -376,22 +385,22 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-4.100>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-4.100>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-4.101",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-4.101>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-4.101>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-4.102",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -400,7 +409,7 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-4.102>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-4.102>
     })
 
@@ -412,8 +421,7 @@ test:do_execsql_test(
 -- Because t2.b has a numeric affinity, type conversion should occur
 -- and the two fields should be equal.
 --
-test:do_execsql_test(
-    "whereB-5.1",
+test:execsql(
     [[
         DROP TABLE t1;
         DROP TABLE t2;
@@ -424,38 +432,43 @@ test:do_execsql_test(
         CREATE TABLE t2(a  INT primary key, b INT);  -- affinity of t2.b is INTEGER
         CREATE INDEX t2b ON t2(b);
         INSERT INTO t2 VALUES(2,99);
+    ]]
+)
 
+test:do_catchsql_test(
+    "whereB-5.1",
+    [[
         SELECT x, a, y=b FROM t1, t2;
     ]],
     {
     -- <whereB-5.1>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-5.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-5.2",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE y=b;
     ]],
     {
     -- <whereB-5.2>
-    1, 2, true
+    1, "Type mismatch: can not convert integer to text"
     -- </whereB-5.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-5.3",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-5.3>
-    1, 2, true
+    1, "Type mismatch: can not convert integer to text"
     -- </whereB-5.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-5.4",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -464,11 +477,11 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-5.4>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-5.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-5.100",
     [[
         DROP INDEX t2b ON t2;
@@ -476,22 +489,22 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-5.100>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-5.100>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-5.101",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-5.101>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-5.101>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-5.102",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -500,7 +513,7 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-5.102>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-5.102>
     })
 
@@ -512,8 +525,8 @@ test:do_execsql_test(
 -- Because t2.b has a numeric affinity, type conversion should occur
 -- and the two fields should be equal.
 --
-test:do_execsql_test(
-    "whereB-6.1",
+
+test:execsql(
     [[
         DROP TABLE t1;
         DROP TABLE t2;
@@ -524,38 +537,43 @@ test:do_execsql_test(
         CREATE TABLE t2(a  INT primary key, b NUMBER);  -- affinity of t2.b is REAL
         CREATE INDEX t2b ON t2(b);
         INSERT INTO t2 VALUES(2,99.0);
+    ]]
+)
 
+test:do_catchsql_test(
+    "whereB-6.1",
+    [[
         SELECT x, a, y=b FROM t1, t2;
     ]],
     {
     -- <whereB-6.1>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-6.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-6.2",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE y=b;
     ]],
     {
     -- <whereB-6.2>
-    1, 2, true
+    1, "Type mismatch: can not convert number to text"
     -- </whereB-6.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-6.3",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-6.3>
-    1, 2, true
+    1, "Type mismatch: can not convert number to text"
     -- </whereB-6.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-6.4",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -564,11 +582,11 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-6.4>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-6.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-6.100",
     [[
         DROP INDEX t2b ON t2;
@@ -576,22 +594,22 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-6.100>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-6.100>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-6.101",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-6.101>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-6.101>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-6.102",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -600,7 +618,7 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-6.102>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-6.102>
     })
 
@@ -612,8 +630,7 @@ test:do_execsql_test(
 -- Because t1.y has a numeric affinity, type conversion should occur
 -- and the two fields should be equal.
 --
-test:do_execsql_test(
-    "whereB-7.1",
+test:execsql(
     [[
         DROP TABLE t1;
         DROP TABLE t2;
@@ -624,38 +641,43 @@ test:do_execsql_test(
         CREATE TABLE t2(a  INT primary key, b SCALAR);  -- affinity of t2.b is NONE
         CREATE INDEX t2b ON t2(b);
         INSERT INTO t2 VALUES(2,'99');
+    ]]
+)
 
+test:do_catchsql_test(
+    "whereB-7.1",
+    [[
         SELECT x, a, y=b FROM t1, t2;
     ]],
     {
     -- <whereB-7.1>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-7.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-7.2",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE y=b;
     ]],
     {
     -- <whereB-7.2>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-7.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-7.3",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-7.3>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-7.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-7.4",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -664,11 +686,11 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-7.4>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-7.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-7.100",
     [[
         DROP INDEX t2b ON t2;
@@ -676,22 +698,22 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-7.100>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-7.100>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-7.101",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-7.101>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-7.101>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-7.102",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -700,7 +722,7 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-7.102>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-7.102>
     })
 
@@ -712,8 +734,7 @@ test:do_execsql_test(
 -- Because t1.y has a numeric affinity, type conversion should occur
 -- and the two fields should be equal.
 --
-test:do_execsql_test(
-    "whereB-8.1",
+test:execsql(
     [[
         DROP TABLE t1;
         DROP TABLE t2;
@@ -724,38 +745,43 @@ test:do_execsql_test(
         CREATE TABLE t2(a  INT primary key, b SCALAR);  -- affinity of t2.b is NONE
         CREATE INDEX t2b ON t2(b);
         INSERT INTO t2 VALUES(2,'99');
+    ]]
+)
 
+test:do_catchsql_test(
+    "whereB-8.1",
+    [[
         SELECT x, a, y=b FROM t1, t2;
     ]],
     {
     -- <whereB-8.1>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-8.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-8.2",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE y=b;
     ]],
     {
     -- <whereB-8.2>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-8.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-8.3",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-8.3>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-8.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-8.4",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -764,11 +790,11 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-8.4>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-8.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-8.100",
     [[
         DROP INDEX t2b ON t2;
@@ -776,22 +802,22 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-8.100>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-8.100>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-8.101",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-8.101>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-8.101>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-8.102",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -800,7 +826,7 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-8.102>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-8.102>
     })
 
@@ -812,8 +838,7 @@ test:do_execsql_test(
 -- Because t1.y has a numeric affinity, type conversion should occur
 -- and the two fields should be equal.
 --
-test:do_execsql_test(
-    "whereB-9.1",
+test:execsql(
     [[
         DROP TABLE t1;
         DROP TABLE t2;
@@ -824,38 +849,43 @@ test:do_execsql_test(
         CREATE TABLE t2(a  INT primary key, b SCALAR);  -- affinity of t2.b is NONE
         CREATE INDEX t2b ON t2(b);
         INSERT INTO t2 VALUES(2,'99');
+    ]]
+)
 
+test:do_catchsql_test(
+    "whereB-9.1",
+    [[
         SELECT x, a, y=b FROM t1, t2;
     ]],
     {
     -- <whereB-9.1>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-9.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-9.2",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE y=b;
     ]],
     {
     -- <whereB-9.2>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-9.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-9.3",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-9.3>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-9.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-9.4",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -864,11 +894,11 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-9.4>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-9.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-9.100",
     [[
         DROP INDEX t2b ON t2;
@@ -876,22 +906,22 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-9.100>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-9.100>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-9.101",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-9.101>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-9.101>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-9.102",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -900,7 +930,7 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-9.102>
-    1, 2, true
+    1, "Type mismatch: can not convert 99 to numeric"
     -- </whereB-9.102>
     })
 
diff --git a/test/sql-tap/whereC.test.lua b/test/sql-tap/whereC.test.lua
index 89459de..58c0495 100755
--- a/test/sql-tap/whereC.test.lua
+++ b/test/sql-tap/whereC.test.lua
@@ -55,9 +55,9 @@ test:do_execsql_test(
 test:test("main", function()
     local data = {{"SELECT i FROM t1 WHERE a=1 AND b=2 AND i>3",         {4, 5}},
                   -- {"SELECT i FROM t1 WHERE rowid='12'",                  {12}},
-                  {"SELECT i FROM t1 WHERE a=1 AND b='2'",               {3, 4, 5}},
-                  {"SELECT i FROM t1 WHERE a=1 AND b='2' AND i>'3'",     {4, 5}},
-                  {"SELECT i FROM t1 WHERE a=1 AND b='2' AND i<5",       {3, 4}},
+                  {"SELECT i FROM t1 WHERE a=1 AND b=2",               {3, 4, 5}},
+                  {"SELECT i FROM t1 WHERE a=1 AND b=2 AND i>3",     {4, 5}},
+                  {"SELECT i FROM t1 WHERE a=1 AND b=2 AND i<5",       {3, 4}},
                   {"SELECT i FROM t1 WHERE a=2 AND b=2 AND i<12",        {10, 11}},
                   {"SELECT i FROM t1 WHERE a IN(1, 2) AND b=2 AND i<11", {3, 4, 5, 10}},
                   {"SELECT i FROM t1 WHERE a=2 AND b=2 AND i BETWEEN 10 AND 12", {10, 11, 12}},
@@ -66,7 +66,7 @@ test:test("main", function()
                   {"SELECT i FROM t1 WHERE a=2 AND b=2 AND i BETWEEN 12 AND 10", {}},
                   {"SELECT i FROM t1 WHERE a=2 AND b=2 AND i<NULL",      {}},
                   {"SELECT i FROM t1 WHERE a=2 AND b=2 AND i>=NULL",     {}},
-                  {"SELECT i FROM t1 WHERE a=1 AND b='2' AND i<4.5",     {3, 4}}}
+                  {"SELECT i FROM t1 WHERE a=1 AND b=2 AND i<4.5",     {3, 4}}}
                   -- {"SELECT i FROM t1 WHERE rowid IS '12'",               {12}}}
 
     for tn, t in ipairs(data) do
diff --git a/test/sql/types.result b/test/sql/types.result
index 54aff46..62161cf 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -339,12 +339,12 @@ box.execute("INSERT INTO tboolean VALUES (TRUE);")
 box.execute("SELECT * FROM tboolean WHERE s1 = x'44';")
 ---
 - null
-- 'Type mismatch: can not convert varbinary to boolean'
+- 'Type mismatch: can not convert boolean to varbinary'
 ...
 box.execute("SELECT * FROM tboolean WHERE s1 = 'abc';")
 ---
 - null
-- 'Type mismatch: can not convert abc to boolean'
+- 'Type mismatch: can not convert boolean to text'
 ...
 box.execute("SELECT * FROM tboolean WHERE s1 = 1;")
 ---
@@ -606,14 +606,6 @@ box.execute("SELECT 18446744073709551615.0 > 18446744073709551615")
   rows:
   - [true]
 ...
-box.execute("SELECT 18446744073709551615 IN ('18446744073709551615', 18446744073709551615.0)")
----
-- metadata:
-  - name: 18446744073709551615 IN ('18446744073709551615', 18446744073709551615.0)
-    type: boolean
-  rows:
-  - [true]
-...
 box.execute("SELECT 1 LIMIT 18446744073709551615;")
 ---
 - metadata:
diff --git a/test/sql/types.test.lua b/test/sql/types.test.lua
index bd14b34..f9603c6 100644
--- a/test/sql/types.test.lua
+++ b/test/sql/types.test.lua
@@ -151,7 +151,6 @@ box.execute("SELECT 18446744073709551610 - 18446744073709551615;")
 box.execute("SELECT 18446744073709551615 = null;")
 box.execute("SELECT 18446744073709551615 = 18446744073709551615.0;")
 box.execute("SELECT 18446744073709551615.0 > 18446744073709551615")
-box.execute("SELECT 18446744073709551615 IN ('18446744073709551615', 18446744073709551615.0)")
 box.execute("SELECT 1 LIMIT 18446744073709551615;")
 box.execute("SELECT 1 LIMIT 1 OFFSET 18446744073709551614;")
 box.execute("SELECT CAST('18446744073' || '709551616' AS INTEGER);")

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Tarantool-patches] [PATCH v1 1/1] sql: remove implicit cast for COMPARISON
  2020-04-21 12:42   ` Mergen Imeev
@ 2020-04-26 18:22     ` Vladislav Shpilevoy
  0 siblings, 0 replies; 8+ messages in thread
From: Vladislav Shpilevoy @ 2020-04-26 18:22 UTC (permalink / raw)
  To: Mergen Imeev; +Cc: tarantool-patches

Hi! Seems like you didn't push the latest version.

> diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
> index 724bc18..34bd38d 100644
> --- a/src/box/sql/vdbe.c
> +++ b/src/box/sql/vdbe.c
> @@ -3471,6 +3459,26 @@ skip_truncate:
>  	assert(oc!=OP_SeekLT || r.default_rc==+1);
>  
>  	r.aMem = &aMem[pOp->p3];
> +	for (int i = 0; i < r.nField; ++i) {
> +		enum field_type type = r.key_def->parts[i].type;
> +		struct Mem *mem = &r.aMem[i];
> +		if ((mem->flags & MEM_Str) != 0 && sql_type_is_numeric(type)) {
> +			diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
> +				field_type_strs[type], mem_type_to_str(mem));
> +			goto abort_due_to_error;
> +		}
> +		if (mem_apply_type(mem, type) != 0) {
> +			diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
> +				field_type_strs[type], mem_type_to_str(mem));
> +			goto abort_due_to_error;
> +		}
> +		if ((mem->flags & MEM_Real) != 0 &&
> +		    (type == FIELD_TYPE_INTEGER ||
> +		     type == FIELD_TYPE_UNSIGNED)) {
> +			res = 1;
> +			goto seek_not_found;
> +		}
> +	}

What is happening in this cycle and the cycle below?

>  #ifdef SQL_DEBUG
>  	{ int i; for(i=0; i<r.nField; i++) assert(memIsValid(&r.aMem[i])); }
>  #endif
> diff --git a/test/sql-tap/in1.test.lua b/test/sql-tap/in1.test.lua
> index 570cc17..e2f4988 100755
> --- a/test/sql-tap/in1.test.lua
> +++ b/test/sql-tap/in1.test.lua
> @@ -637,12 +637,12 @@ test:do_test(
>      "in-11.2",
>      function()
>          -- The '2' should be coerced into 2 because t6.b is NUMERIC

The comment is irrelevant now. And therefore the test probably too. Please,
locate all other tests, which become wrong after this commit, and fix their
comments or remove completely.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Tarantool-patches] [PATCH v1 1/1] sql: remove implicit cast for COMPARISON
@ 2020-02-20  8:00 imeevma
  0 siblings, 0 replies; 8+ messages in thread
From: imeevma @ 2020-02-20  8:00 UTC (permalink / raw)
  To: korablev; +Cc: tarantool-patches

This patch disables implicit casting for COMPARISON.

Part of #4230

@TarantoolBot document
Title: Comparison rules in Tarantool-SQL
Let's say we currently have the following primitive types in
Tarantool-SQL: INTEGER, DOUBLE, STRING, BOOLEAN, VARBINARY. Any
value of any type available in SQL can be assigned to one of these
primitive types.

In these terms, the new rules for comparison are:
1) NULL of any type can be compared to any value. The result is
always NULL.
2) Any values of primitive types INTEGER or DOUBLE can be compared
with each other.
3) Values of the same primitive type can be compared with each
other.
4) In any other case values cannot be compared. An error is
generated.
---
https://github.com/tarantool/tarantool/issues/4230
https://github.com/tarantool/tarantool/tree/imeevma/gh-4230-remove-implicit-cast-for-comparison

 src/box/sql/vdbe.c                                 |  262 +-
 src/box/tuple_compare.cc                           |   13 +-
 src/box/tuple_compare.h                            |   15 +
 test/sql-tap/identifier_case.test.lua              |   10 +-
 test/sql-tap/in1.test.lua                          |   13 +-
 test/sql-tap/in4.test.lua                          |   18 +-
 test/sql-tap/index1.test.lua                       |    4 +-
 test/sql-tap/insert3.test.lua                      |    7 +-
 test/sql-tap/intpkey.test.lua                      |    4 +-
 test/sql-tap/join.test.lua                         |    4 +-
 test/sql-tap/misc1.test.lua                        |   30 +-
 test/sql-tap/select1.test.lua                      |    6 +-
 test/sql-tap/select7.test.lua                      |    2 +-
 test/sql-tap/sql-errors.test.lua                   |    4 +-
 test/sql-tap/subquery.test.lua                     |    2 +-
 test/sql-tap/tkt-9a8b09f8e6.test.lua               |   27 +-
 test/sql-tap/tkt-f973c7ac31.test.lua               |   16 +-
 test/sql-tap/tkt-fc7bd6358f.test.lua               |   16 +-
 test/sql-tap/tkt3493.test.lua                      |   32 +-
 test/sql-tap/transitive1.test.lua                  |   12 +-
 test/sql-tap/where2.test.lua                       |   30 +-
 test/sql-tap/where5.test.lua                       |   12 +-
 test/sql-tap/whereB.test.lua                       |  222 +-
 test/sql-tap/whereC.test.lua                       |    8 +-
 test/sql/boolean.result                            |  220 +-
 ...4230-remove-implicit-cast-for-comparison.result | 6519 ++++++++++++++++++++
 ...30-remove-implicit-cast-for-comparison.test.sql |  953 +++
 test/sql/types.result                              |    4 +-
 test/sql/types.test.lua                            |    2 +-
 29 files changed, 7915 insertions(+), 552 deletions(-)
 create mode 100644 test/sql/gh-4230-remove-implicit-cast-for-comparison.result
 create mode 100644 test/sql/gh-4230-remove-implicit-cast-for-comparison.test.sql

diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 620d74e..fbb4bdc 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -44,6 +44,7 @@
 #include "box/fk_constraint.h"
 #include "box/txn.h"
 #include "box/tuple.h"
+#include "box/tuple_compare.h"
 #include "box/port.h"
 #include "sqlInt.h"
 #include "vdbeInt.h"
@@ -2050,15 +2051,15 @@ case OP_Cast: {                  /* in1 */
  * jump to address P2.  Or if the SQL_STOREP2 flag is set in P5, then
  * store the result of comparison in register P2.
  *
- * Once any conversions have taken place, and neither value is NULL,
- * the values are compared. If both values are blobs then memcmp() is
- * used to determine the results of the comparison.  If both values
- * are text, then the appropriate collating function specified in
- * P4 is used to do the comparison.  If P4 is not specified then
- * memcmp() is used to compare text string.  If both values are
- * numeric, then a numeric comparison is used. If the two values
- * are of different types, then numbers are considered less than
- * strings and strings are considered less than blobs.
+ * If neither value is NULL, the values are compared. If both
+ * values are blobs then memcmp() is used to determine the results
+ * of the comparison. If both values are booleans, TRUE if more
+ * than FALSE. If both values are text, then the appropriate
+ * collating function specified in P4 is used to do the
+ * comparison. If P4 is not specified then memcmp() is used to
+ * compare text string. If both values are numeric, then a numeric
+ * comparison is used. If both values are not NULL and the above
+ * rules cannot be applied to them, an error is generated.
  *
  * If SQL_NULLEQ is set in P5 then the result of comparison is always either
  * true or false and is never NULL.  If both operands are NULL then the result
@@ -2096,15 +2097,8 @@ case OP_Cast: {                  /* in1 */
  * reg(P3) is NULL then the take the jump.  If the SQL_JUMPIFNULL
  * bit is clear then fall through if either operand is NULL.
  *
- * Once any conversions have taken place, and neither value is NULL,
- * the values are compared. If both values are blobs then memcmp() is
- * used to determine the results of the comparison.  If both values
- * are text, then the appropriate collating function specified in
- * P4 is  used to do the comparison.  If P4 is not specified then
- * memcmp() is used to compare text string.  If both values are
- * numeric, then a numeric comparison is used. If the two values
- * are of different types, then numbers are considered less than
- * strings and strings are considered less than blobs.
+ * See the Eq opcode for additional information about comparison
+ * rules.
  */
 /* Opcode: Le P1 P2 P3 P4 P5
  * Synopsis: IF r[P3]<=r[P1]
@@ -2133,189 +2127,103 @@ case OP_Lt:               /* same as TK_LT, jump, in1, in3 */
 case OP_Le:               /* same as TK_LE, jump, in1, in3 */
 case OP_Gt:               /* same as TK_GT, jump, in1, in3 */
 case OP_Ge: {             /* same as TK_GE, jump, in1, in3 */
-	int res, res2;      /* Result of the comparison of pIn1 against pIn3 */
-	u32 flags1;         /* Copy of initial value of pIn1->flags */
-	u32 flags3;         /* Copy of initial value of pIn3->flags */
-
+	/*
+	 * Result of comparison: more than 0 if l > r,
+	 * 0 if l == r, less than 0 if l < r.
+	 */
+	int cmp_res;
+	/* Result of the operation. */
+	bool result;
 	pIn1 = &aMem[pOp->p1];
 	pIn3 = &aMem[pOp->p3];
-	flags1 = pIn1->flags;
-	flags3 = pIn3->flags;
-	enum field_type ft_p1 = pIn1->field_type;
-	enum field_type ft_p3 = pIn3->field_type;
-	if ((flags1 | flags3)&MEM_Null) {
-		/* One or both operands are NULL */
-		if (pOp->p5 & SQL_NULLEQ) {
-			/* If SQL_NULLEQ is set (which will only happen if the operator is
-			 * OP_Eq or OP_Ne) then take the jump or not depending on whether
-			 * or not both operands are null.
-			 */
-			assert(pOp->opcode==OP_Eq || pOp->opcode==OP_Ne);
-			assert((flags1 & MEM_Cleared)==0);
-			assert((pOp->p5 & SQL_JUMPIFNULL)==0);
-			if ((flags1&flags3&MEM_Null)!=0
-			    && (flags3&MEM_Cleared)==0
-				) {
-				res = 0;  /* Operands are equal */
-			} else {
-				res = 1;  /* Operands are not equal */
-			}
-		} else {
-			/* SQL_NULLEQ is clear and at least one operand is NULL,
-			 * then the result is always NULL.
-			 * The jump is taken if the SQL_JUMPIFNULL bit is set.
+	enum mp_class lclass = mp_classof(sql_value_type(&aMem[pOp->p1]));
+	enum mp_class rclass = mp_classof(sql_value_type(&aMem[pOp->p3]));
+	assert(lclass != MP_CLASS_MAP && rclass != MP_CLASS_MAP);
+	assert(lclass != MP_CLASS_ARRAY && rclass != MP_CLASS_ARRAY);
+	assert(lclass != mp_class_max && rclass != mp_class_max);
+	if (lclass == MP_CLASS_NIL || rclass == MP_CLASS_NIL) {
+		if ((pOp->p5 & SQL_NULLEQ) == 0) {
+			/*
+			 * SQL_NULLEQ is clear and at least one
+			 * operand is NULL, then the result is
+			 * always NULL. The jump is taken if the
+			 * SQL_JUMPIFNULL bit is set.
 			 */
 			if (pOp->p5 & SQL_STOREP2) {
 				pOut = vdbe_prepare_null_out(p, pOp->p2);
-				iCompare = 1;    /* Operands are not equal */
+				iCompare = 1;
 				REGISTER_TRACE(p, pOp->p2, pOut);
 			} else {
 				VdbeBranchTaken(2,3);
-				if (pOp->p5 & SQL_JUMPIFNULL) {
+				if (pOp->p5 & SQL_JUMPIFNULL)
 					goto jump_to_p2;
-				}
 			}
 			break;
 		}
-	} else if (((flags1 | flags3) & MEM_Bool) != 0 ||
-		   ((flags1 | flags3) & MEM_Blob) != 0) {
 		/*
-		 * If one of values is of type BOOLEAN or VARBINARY,
-		 * then the second one must be of the same type as
-		 * well. Otherwise an error is raised.
+		 * If SQL_NULLEQ is set (which will only happen if
+		 * the operator is OP_Eq or OP_Ne) then take the
+		 * jump or not depending on whether or not both
+		 * operands are null.
 		 */
-		int type_arg1 = flags1 & (MEM_Bool | MEM_Blob);
-		int type_arg3 = flags3 & (MEM_Bool | MEM_Blob);
-		if (type_arg1 != type_arg3) {
-			char *inconsistent_type = type_arg1 != 0 ?
-						  mem_type_to_str(pIn3) :
-						  mem_type_to_str(pIn1);
-			char *expected_type     = type_arg1 != 0 ?
-						  mem_type_to_str(pIn1) :
-						  mem_type_to_str(pIn3);
-			diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
-				 inconsistent_type, expected_type);
-			goto abort_due_to_error;
-		}
-		res = sqlMemCompare(pIn3, pIn1, NULL);
+		assert(pOp->opcode == OP_Eq || pOp->opcode == OP_Ne);
+		assert((pOp->p5 & SQL_JUMPIFNULL) == 0);
+		cmp_res = !(lclass == MP_CLASS_NIL && rclass == MP_CLASS_NIL);
+	} else if (lclass == rclass) {
+		cmp_res = sqlMemCompare(pIn3, pIn1, pOp->p4.pColl);
 	} else {
-		enum field_type type = pOp->p5 & FIELD_TYPE_MASK;
-		if (sql_type_is_numeric(type)) {
-			if ((flags1 | flags3)&MEM_Str) {
-				if ((flags1 & MEM_Str) == MEM_Str) {
-					mem_apply_numeric_type(pIn1);
-					testcase( flags3!=pIn3->flags); /* Possible if pIn1==pIn3 */
-					flags3 = pIn3->flags;
-				}
-				if ((flags3 & MEM_Str) == MEM_Str) {
-					if (mem_apply_numeric_type(pIn3) != 0) {
-						diag_set(ClientError,
-							 ER_SQL_TYPE_MISMATCH,
-							 sql_value_to_diag_str(pIn3),
-							 "numeric");
-						goto abort_due_to_error;
-					}
-
-				}
-			}
-			/* Handle the common case of integer comparison here, as an
-			 * optimization, to avoid a call to sqlMemCompare()
-			 */
-			if ((pIn1->flags & pIn3->flags & (MEM_Int | MEM_UInt)) != 0) {
-				if ((pIn1->flags & pIn3->flags & MEM_Int) != 0) {
-					if (pIn3->u.i > pIn1->u.i)
-						res = +1;
-					else if (pIn3->u.i < pIn1->u.i)
-						res = -1;
-					else
-						res = 0;
-					goto compare_op;
-				}
-				if ((pIn1->flags & pIn3->flags & MEM_UInt) != 0) {
-					if (pIn3->u.u > pIn1->u.u)
-						res = +1;
-					else if (pIn3->u.u < pIn1->u.u)
-						res = -1;
-					else
-						res = 0;
-					goto compare_op;
-				}
-				if ((pIn1->flags & MEM_UInt) != 0 &&
-				    (pIn3->flags & MEM_Int) != 0) {
-					res = -1;
-					goto compare_op;
-				}
-				res = 1;
-				goto compare_op;
-			}
-		} else if (type == FIELD_TYPE_STRING) {
-			if ((flags1 & MEM_Str) == 0 &&
-			    (flags1 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
-				testcase( pIn1->flags & MEM_Int);
-				testcase( pIn1->flags & MEM_Real);
-				sqlVdbeMemStringify(pIn1);
-				testcase( (flags1&MEM_Dyn) != (pIn1->flags&MEM_Dyn));
-				flags1 = (pIn1->flags & ~MEM_TypeMask) | (flags1 & MEM_TypeMask);
-				assert(pIn1!=pIn3);
-			}
-			if ((flags3 & MEM_Str) == 0 &&
-			    (flags3 & (MEM_Int | MEM_UInt | MEM_Real)) != 0) {
-				testcase( pIn3->flags & MEM_Int);
-				testcase( pIn3->flags & MEM_Real);
-				sqlVdbeMemStringify(pIn3);
-				testcase( (flags3&MEM_Dyn) != (pIn3->flags&MEM_Dyn));
-				flags3 = (pIn3->flags & ~MEM_TypeMask) | (flags3 & MEM_TypeMask);
-			}
-		}
-		assert(pOp->p4type==P4_COLLSEQ || pOp->p4.pColl==0);
-		res = sqlMemCompare(pIn3, pIn1, pOp->p4.pColl);
-	}
-			compare_op:
-	switch( pOp->opcode) {
-	case OP_Eq:    res2 = res==0;     break;
-	case OP_Ne:    res2 = res;        break;
-	case OP_Lt:    res2 = res<0;      break;
-	case OP_Le:    res2 = res<=0;     break;
-	case OP_Gt:    res2 = res>0;      break;
-	default:       res2 = res>=0;     break;
+		diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+			 mem_type_to_str(pIn1), mem_type_to_str(pIn3));
+		goto abort_due_to_error;
 	}
 
-	/* Undo any changes made by mem_apply_type() to the input registers. */
-	assert((pIn1->flags & MEM_Dyn) == (flags1 & MEM_Dyn));
-	pIn1->flags = flags1;
-	pIn1->field_type = ft_p1;
-	assert((pIn3->flags & MEM_Dyn) == (flags3 & MEM_Dyn));
-	pIn3->flags = flags3;
-	pIn3->field_type = ft_p3;
+	switch (pOp->opcode) {
+	case OP_Eq:
+		result = cmp_res == 0;
+		break;
+	case OP_Ne:
+		result = cmp_res != 0;
+		break;
+	case OP_Lt:
+		result = cmp_res < 0;
+		break;
+	case OP_Le:
+		result = cmp_res <= 0;
+		break;
+	case OP_Gt:
+		result = cmp_res > 0;
+		break;
+	case OP_Ge:
+		result = cmp_res >= 0;
+		break;
+	default:
+		unreachable();
+	}
 
 	if (pOp->p5 & SQL_STOREP2) {
-		iCompare = res;
-		res2 = res2!=0;  /* For this path res2 must be exactly 0 or 1 */
-		if ((pOp->p5 & SQL_KEEPNULL)!=0) {
-			/* The KEEPNULL flag prevents OP_Eq from overwriting a NULL with true
-			 * and prevents OP_Ne from overwriting NULL with false.  This flag
-			 * is only used in contexts where either:
-			 *   (1) op==OP_Eq && (r[P2]==NULL || r[P2]==0)
-			 *   (2) op==OP_Ne && (r[P2]==NULL || r[P2]==1)
-			 * Therefore it is not necessary to check the content of r[P2] for
-			 * NULL.
-			 */
-			assert(pOp->opcode==OP_Ne || pOp->opcode==OP_Eq);
-			assert(res2==0 || res2==1);
-			testcase( res2==0 && pOp->opcode==OP_Eq);
-			testcase( res2==1 && pOp->opcode==OP_Eq);
-			testcase( res2==0 && pOp->opcode==OP_Ne);
-			testcase( res2==1 && pOp->opcode==OP_Ne);
-			if ((pOp->opcode==OP_Eq)==res2) break;
+		iCompare = cmp_res;
+		/*
+		 * The KEEPNULL flag prevents OP_Eq from
+		 * overwriting a NULL with true and prevents OP_Ne
+		 * from overwriting NULL with false. This flag
+		 * is only used in contexts where either:
+		 *   (1) op==OP_Eq && (r[P2]==NULL || r[P2]==0)
+		 *   (2) op==OP_Ne && (r[P2]==NULL || r[P2]==1)
+		 * Therefore it is not necessary to check the
+		 * content of r[P2] for NULL.
+		 */
+		if ((pOp->p5 & SQL_KEEPNULL) != 0) {
+			assert(pOp->opcode == OP_Ne || pOp->opcode == OP_Eq);
+			if ((pOp->opcode == OP_Eq) == result)
+				break;
 		}
 		pOut = vdbe_prepare_null_out(p, pOp->p2);
-		mem_set_bool(pOut, res2);
+		mem_set_bool(pOut, result);
 		REGISTER_TRACE(p, pOp->p2, pOut);
 	} else {
-		VdbeBranchTaken(res!=0, (pOp->p5 & SQL_NULLEQ)?2:3);
-		if (res2) {
+		VdbeBranchTaken(cmp_res != 0, (pOp->p5 & SQL_NULLEQ) ? 2 : 3);
+		if (result)
 			goto jump_to_p2;
-		}
 	}
 	break;
 }
diff --git a/src/box/tuple_compare.cc b/src/box/tuple_compare.cc
index 3f8a0ce..90fd380 100644
--- a/src/box/tuple_compare.cc
+++ b/src/box/tuple_compare.cc
@@ -68,17 +68,6 @@ hint_cmp(hint_t hint_a, hint_t hint_b)
 inline __attribute__((always_inline)) int
 mp_compare_uint(const char **data_a, const char **data_b);
 
-enum mp_class {
-	MP_CLASS_NIL = 0,
-	MP_CLASS_BOOL,
-	MP_CLASS_NUMBER,
-	MP_CLASS_STR,
-	MP_CLASS_BIN,
-	MP_CLASS_ARRAY,
-	MP_CLASS_MAP,
-	mp_class_max,
-};
-
 static enum mp_class mp_classes[] = {
 	/* .MP_NIL     = */ MP_CLASS_NIL,
 	/* .MP_UINT    = */ MP_CLASS_NUMBER,
@@ -98,7 +87,7 @@ static enum mp_class mp_ext_classes[] = {
 	/* .MP_DECIMAL		 = */ MP_CLASS_NUMBER,
 };
 
-static enum mp_class
+enum mp_class
 mp_classof(enum mp_type type)
 {
 	return mp_classes[type];
diff --git a/src/box/tuple_compare.h b/src/box/tuple_compare.h
index 8614f23..2a4d44d 100644
--- a/src/box/tuple_compare.h
+++ b/src/box/tuple_compare.h
@@ -31,11 +31,26 @@
  * SUCH DAMAGE.
  */
 #include <stdint.h>
+#include <msgpuck.h>
 
 #if defined(__cplusplus)
 extern "C" {
 #endif /* defined(__cplusplus) */
 
+enum mp_class {
+	MP_CLASS_NIL = 0,
+	MP_CLASS_BOOL,
+	MP_CLASS_NUMBER,
+	MP_CLASS_STR,
+	MP_CLASS_BIN,
+	MP_CLASS_ARRAY,
+	MP_CLASS_MAP,
+	mp_class_max,
+};
+
+enum mp_class
+mp_classof(enum mp_type type);
+
 struct key_def;
 
 /**
diff --git a/test/sql-tap/identifier_case.test.lua b/test/sql-tap/identifier_case.test.lua
index 2a00626..5e60b6f 100755
--- a/test/sql-tap/identifier_case.test.lua
+++ b/test/sql-tap/identifier_case.test.lua
@@ -242,11 +242,11 @@ data = {
     { 2,  [[ 'a' < 'b' collate "binary" ]], {0, {true}}},
     { 3,  [[ 'a' < 'b' collate 'binary' ]], {1, [[Syntax error at line 1 near ''binary'']]}},
     { 4,  [[ 'a' < 'b' collate "unicode" ]], {0, {true}}},
-    { 5,  [[ 5 < 'b' collate "unicode" ]], {0, {true}}},
-    { 6,  [[ 5 < 'b' collate unicode ]], {1,"Collation 'UNICODE' does not exist"}},
-    { 7,  [[ 5 < 'b' collate "unicode_ci" ]], {0, {true}}},
-    { 8,  [[ 5 < 'b' collate NONE ]], {1, "Collation 'NONE' does not exist"}},
-    { 9,  [[ 5 < 'b' collate "none" ]], {0, {true}}},
+    { 5,  [[ '5' < 'b' collate "unicode" ]], {0, {true}}},
+    { 6,  [[ '5' < 'b' collate unicode ]], {1,"Collation 'UNICODE' does not exist"}},
+    { 7,  [[ '5' < 'b' collate "unicode_ci" ]], {0, {true}}},
+    { 8,  [[ '5' < 'b' collate NONE ]], {1, "Collation 'NONE' does not exist"}},
+    { 9,  [[ '5' < 'b' collate "none" ]], {0, {true}}},
 }
 
 for _, row in ipairs(data) do
diff --git a/test/sql-tap/in1.test.lua b/test/sql-tap/in1.test.lua
index 570cc17..4b20c65 100755
--- a/test/sql-tap/in1.test.lua
+++ b/test/sql-tap/in1.test.lua
@@ -633,16 +633,13 @@ test:do_execsql_test(
         -- </in-11.1>
     })
 
-test:do_test(
+test:do_catchsql_test(
     "in-11.2",
-    function()
-        -- The '2' should be coerced into 2 because t6.b is NUMERIC
-        return test:execsql [[
-            SELECT * FROM t6 WHERE b IN ('2');
-        ]]
-    end, {
+    [[
+        SELECT * FROM t6 WHERE b IN ('2');
+    ]], {
         -- <in-11.2>
-        1, 2
+        1, "Type mismatch: can not convert text to unsigned"
         -- </in-11.2>
     })
 
diff --git a/test/sql-tap/in4.test.lua b/test/sql-tap/in4.test.lua
index 8c69173..1c121ae 100755
--- a/test/sql-tap/in4.test.lua
+++ b/test/sql-tap/in4.test.lua
@@ -590,7 +590,7 @@ test:do_execsql_test(
     [[
         CREATE TABLE t4b(a TEXT, b NUMBER, c  INT PRIMARY KEY);
         INSERT INTO t4b VALUES('1.0',1,4);
-        SELECT c FROM t4b WHERE a=b;
+        SELECT c FROM t4b WHERE CAST(a AS NUMBER) = b;
     ]], {
         -- <in4-4.11>
         4
@@ -600,7 +600,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "in4-4.12",
     [[
-        SELECT c FROM t4b WHERE b=a;
+        SELECT c FROM t4b WHERE b=CAST(a AS NUMBER);
     ]], {
         -- <in4-4.12>
         4
@@ -610,7 +610,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "in4-4.13",
     [[
-        SELECT c FROM t4b WHERE +a=b;
+        SELECT c FROM t4b WHERE +CAST(a AS NUMBER)=b;
     ]], {
         -- <in4-4.13>
         4
@@ -620,7 +620,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "in4-4.14",
     [[
-        SELECT c FROM t4b WHERE a=+b;
+        SELECT c FROM t4b WHERE CAST(a AS NUMBER)=+b;
     ]], {
         -- <in4-4.14>
         4
@@ -630,7 +630,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "in4-4.15",
     [[
-        SELECT c FROM t4b WHERE +b=a;
+        SELECT c FROM t4b WHERE +b=CAST(a AS NUMBER);
     ]], {
         -- <in4-4.15>
         4
@@ -640,7 +640,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "in4-4.16",
     [[
-        SELECT c FROM t4b WHERE b=+a;
+        SELECT c FROM t4b WHERE b=+CAST(a AS NUMBER);
     ]], {
         -- <in4-4.16>
         4
@@ -650,7 +650,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "in4-4.17",
     [[
-        SELECT c FROM t4b WHERE a IN (b);
+        SELECT c FROM t4b WHERE CAST(a AS NUMBER) IN (b);
     ]], {
         -- <in4-4.17>
         4
@@ -660,7 +660,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "in4-4.18",
     [[
-        SELECT c FROM t4b WHERE b IN (a);
+        SELECT c FROM t4b WHERE b IN (CAST(a AS NUMBER));
     ]], {
         -- <in4-4.18>
         4
@@ -670,7 +670,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "in4-4.19",
     [[
-        SELECT c FROM t4b WHERE +b IN (a);
+        SELECT c FROM t4b WHERE +b IN (CAST(a AS NUMBER));
     ]], {
         -- <in4-4.19>
         4
diff --git a/test/sql-tap/index1.test.lua b/test/sql-tap/index1.test.lua
index e173e68..85988c9 100755
--- a/test/sql-tap/index1.test.lua
+++ b/test/sql-tap/index1.test.lua
@@ -785,7 +785,7 @@ test:do_catchsql_test(
         SELECT c FROM t6 WHERE a>123;
     ]], {
         -- <index-14.6>
-        1, "Type mismatch: can not convert  to numeric"
+        1, "Type mismatch: can not convert unsigned to text"
         -- </index-14.6>
     })
 
@@ -795,7 +795,7 @@ test:do_catchsql_test(
         SELECT c FROM t6 WHERE a>=123;
     ]], {
         -- <index-14.7>
-        1, "Type mismatch: can not convert  to numeric"
+        1, "Type mismatch: can not convert unsigned to text"
         -- </index-14.7>
     })
 
diff --git a/test/sql-tap/insert3.test.lua b/test/sql-tap/insert3.test.lua
index 43bb066..41f1e57 100755
--- a/test/sql-tap/insert3.test.lua
+++ b/test/sql-tap/insert3.test.lua
@@ -59,8 +59,8 @@ test:do_execsql_test(
     [[
             CREATE TABLE log2(rowid INTEGER PRIMARY KEY AUTOINCREMENT, x TEXT UNIQUE,y INT );
             CREATE TRIGGER r2 BEFORE INSERT ON t1 FOR EACH ROW BEGIN
-              UPDATE log2 SET y=y+1 WHERE x=new.b;
-              INSERT OR IGNORE INTO log2(x, y) VALUES(new.b,1);
+              UPDATE log2 SET y = y+1 WHERE CAST(x AS NUMBER) = new.b;
+              INSERT OR IGNORE INTO log2(x, y) VALUES(CAST(new.b AS STRING),1);
             END;
             INSERT INTO t1(a, b) VALUES('hi', 453);
             SELECT x,y FROM log ORDER BY x;
@@ -84,8 +84,7 @@ test:do_execsql_test(
     "insert3-1.4.1",
     [[
             INSERT INTO t1(a,b) SELECT a,b FROM t1;
-            SELECT 'a:', x, y FROM log UNION ALL
-                SELECT 'b:', x, y FROM log2 ORDER BY x;
+            SELECT 'a:', x, y FROM log UNION ALL SELECT 'b:', x, y FROM log2 ORDER BY x;
     ]], {
         -- <insert3-1.4.1>
         "b:","1",1,"b:","11",1,"b:","15",1,"b:","453",2,"a:","5",4,"b:","5",1,"a:","hello",4,"a:","hi",2
diff --git a/test/sql-tap/intpkey.test.lua b/test/sql-tap/intpkey.test.lua
index bec2670..4403c57 100755
--- a/test/sql-tap/intpkey.test.lua
+++ b/test/sql-tap/intpkey.test.lua
@@ -882,7 +882,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "intpkey-14.5",
     [[
-        SELECT * FROM t3 WHERE a<c;
+        SELECT * FROM t3 WHERE CAST(a AS STRING) < c;
     ]], {
         -- <intpkey-14.5>
         1, 1, "one"
@@ -892,7 +892,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "intpkey-14.6",
     [[
-        SELECT * FROM t3 WHERE a=c;
+        SELECT * FROM t3 WHERE CAST(a AS STRING) = c;
     ]], {
         -- <intpkey-14.6>
         2, 2, "2", 3, 3, "3"
diff --git a/test/sql-tap/join.test.lua b/test/sql-tap/join.test.lua
index 4f014e0..a9d4300 100755
--- a/test/sql-tap/join.test.lua
+++ b/test/sql-tap/join.test.lua
@@ -1015,7 +1015,7 @@ test:do_test(
             DROP TABLE IF EXISTS t2;
         ]]
         return test:execsql [[
-            CREATE TABLE t1(a TEXT primary key, b TEXT);
+            CREATE TABLE t1(a TEXT primary key, b INTEGER);
             CREATE TABLE t2(b INTEGER primary key, a TEXT);
             INSERT INTO t1 VALUES('one', '1.0');
             INSERT INTO t1 VALUES('two', '2');
@@ -1034,7 +1034,7 @@ test:do_execsql_test(
         SELECT * FROM t1 NATURAL JOIN t2 
     ]], {
         -- <join-11.9>
-        "one", "1.0", "two", "2"
+        "one", 1.0, "two", 2
         -- </join-11.9>
     })
 
diff --git a/test/sql-tap/misc1.test.lua b/test/sql-tap/misc1.test.lua
index 32f38cc..bb6e9a1 100755
--- a/test/sql-tap/misc1.test.lua
+++ b/test/sql-tap/misc1.test.lua
@@ -88,7 +88,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "misc1-1.4",
     [[
-        SELECT x75 FROM manycol WHERE x50=350
+        SELECT x75 FROM manycol WHERE x50='350'
     ]], {
         -- <misc1-1.4>
         "375"
@@ -98,7 +98,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "misc1-1.5",
     [[
-        SELECT x50 FROM manycol WHERE x99=599
+        SELECT x50 FROM manycol WHERE x99='599'
     ]], {
         -- <misc1-1.5>
         "550"
@@ -109,7 +109,7 @@ test:do_test(
     "misc1-1.6",
     function()
         test:execsql("CREATE INDEX manycol_idx1 ON manycol(x99)")
-        return test:execsql("SELECT x50 FROM manycol WHERE x99=899")
+        return test:execsql("SELECT x50 FROM manycol WHERE x99='899'")
     end, {
         -- <misc1-1.6>
         "850"
@@ -129,7 +129,7 @@ test:do_execsql_test(
 test:do_test(
     "misc1-1.8",
     function()
-        test:execsql("DELETE FROM manycol WHERE x98=1234")
+        test:execsql("DELETE FROM manycol WHERE x98='1234'")
         return test:execsql("SELECT count(*) FROM manycol")
     end, {
         -- <misc1-1.8>
@@ -140,7 +140,7 @@ test:do_test(
 test:do_test(
     "misc1-1.9",
     function()
-        test:execsql("DELETE FROM manycol WHERE x98=998")
+        test:execsql("DELETE FROM manycol WHERE x98='998'")
         return test:execsql("SELECT count(*) FROM manycol")
     end, {
         -- <misc1-1.9>
@@ -151,7 +151,7 @@ test:do_test(
 test:do_test(
     "misc1-1.10",
     function()
-        test:execsql("DELETE FROM manycol WHERE x99=500")
+        test:execsql("DELETE FROM manycol WHERE x99='500'")
         return test:execsql("SELECT count(*) FROM manycol")
     end, {
         -- <misc1-1.10>
@@ -162,7 +162,7 @@ test:do_test(
 test:do_test(
     "misc1-1.11",
     function()
-        test:execsql("DELETE FROM manycol WHERE x99=599")
+        test:execsql("DELETE FROM manycol WHERE x99='599'")
         return test:execsql("SELECT count(*) FROM manycol")
     end, {
         -- <misc1-1.11>
@@ -479,9 +479,9 @@ local where = ""
 test:do_test(
     "misc1-10.1",
     function()
-        where = "WHERE x0>=0"
+        where = "WHERE x0>='0'"
         for i = 1, 99, 1 do
-            where = where .. " AND x"..i.."<>0"
+            where = where .. " AND x"..i.."<>'0'"
         end
         return test:catchsql("SELECT count(*) FROM manycol "..where.."")
     end, {
@@ -496,7 +496,7 @@ test:do_test(
 test:do_test(
     "misc1-10.3",
     function()
-        where = string.gsub(where,"x0>=0", "x0=0")
+        where = string.gsub(where,"x0>='0'", "x0='0'")
         return test:catchsql("DELETE FROM manycol "..where.."")
     end, {
         -- <misc1-10.3>
@@ -520,7 +520,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "misc1-10.6",
     [[
-        SELECT x1 FROM manycol WHERE x0=100
+        SELECT x1 FROM manycol WHERE x0='100'
     ]], {
         -- <misc1-10.6>
         "101"
@@ -530,7 +530,7 @@ test:do_execsql_test(
 test:do_test(
     "misc1-10.7",
     function()
-        where = string.gsub(where, "x0=0", "x0=100")
+        where = string.gsub(where, "x0='0'", "x0='100'")
         return test:catchsql("UPDATE manycol SET x1=x1+1 "..where.."")
     end, {
         -- <misc1-10.7>
@@ -541,7 +541,7 @@ test:do_test(
 test:do_execsql_test(
     "misc1-10.8",
     [[
-        SELECT x1 FROM manycol WHERE x0=100
+        SELECT x1 FROM manycol WHERE x0='100'
     ]], {
         -- <misc1-10.8>
         "102"
@@ -563,7 +563,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "misc1-10.10",
     [[
-        SELECT x1 FROM manycol WHERE x0=100
+        SELECT x1 FROM manycol WHERE x0='100'
     ]], {
         -- <misc1-10.10>
         "103"
@@ -622,7 +622,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "misc1-12.2",
     [[
-        SELECT '0'==0.0
+        SELECT CAST('0' AS NUMBER)==0.0
     ]], {
         -- <misc1-12.2>
         true
diff --git a/test/sql-tap/select1.test.lua b/test/sql-tap/select1.test.lua
index fbebfab..a98a3bc 100755
--- a/test/sql-tap/select1.test.lua
+++ b/test/sql-tap/select1.test.lua
@@ -320,7 +320,7 @@ test:do_catchsql_test(
         SELECT count(*),count(a),count(b) FROM t4 WHERE b=5
     ]], {
         -- <select1-2.5.3>
-        1, "Type mismatch: can not convert This is a string that is too big to fit inside a NBFS buffer to numeric"
+        1, "Type mismatch: can not convert unsigned to text"
         -- </select1-2.5.3>
     })
 
@@ -1912,7 +1912,7 @@ test:do_execsql_test(
 test:do_execsql_test(
         "select1-12.7",
         [[
-            SELECT * FROM t3 WHERE a=(SELECT 1);
+            SELECT * FROM t3 WHERE a=(SELECT '1');
         ]], {
             -- <select1-12.7>
             0, "1", "2"
@@ -1922,7 +1922,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "select1-12.8",
     [[
-        SELECT * FROM t3 WHERE a=(SELECT 2);
+        SELECT * FROM t3 WHERE a=(SELECT '2');
     ]], {
         -- <select1-12.8>
 
diff --git a/test/sql-tap/select7.test.lua b/test/sql-tap/select7.test.lua
index fec5d7a..d1fde71 100755
--- a/test/sql-tap/select7.test.lua
+++ b/test/sql-tap/select7.test.lua
@@ -256,7 +256,7 @@ test:do_execsql_test(
         DROP TABLE IF EXISTS t5;
         CREATE TABLE t5(a TEXT primary key, b INT);
         INSERT INTO t5 VALUES(123, 456);
-        SELECT typeof(a), a FROM t5 GROUP BY a HAVING a<b;
+        SELECT typeof(a), a FROM t5 GROUP BY a HAVING CAST(a AS NUMBER)<b;
     ]], {
         -- <select7-7.7>
         "string", "123"
diff --git a/test/sql-tap/sql-errors.test.lua b/test/sql-tap/sql-errors.test.lua
index 5ec94bf..8ea6f8b 100755
--- a/test/sql-tap/sql-errors.test.lua
+++ b/test/sql-tap/sql-errors.test.lua
@@ -765,7 +765,7 @@ test:do_catchsql_test(
 		SELECT X'ff' >= false;
 	]], {
 		-- <sql-errors-2.8>
-		1, "Type mismatch: can not convert varbinary to boolean"
+		1, "Type mismatch: can not convert boolean to varbinary"
 		-- </sql-errors-2.8>
 	})
 
@@ -775,7 +775,7 @@ test:do_catchsql_test(
 		SELECT X'ff' <= false;
 	]], {
 		-- <sql-errors-2.9>
-		1, "Type mismatch: can not convert varbinary to boolean"
+		1, "Type mismatch: can not convert boolean to varbinary"
 		-- </sql-errors-2.9>
 	})
 
diff --git a/test/sql-tap/subquery.test.lua b/test/sql-tap/subquery.test.lua
index 6bedf58..ec10e6a 100755
--- a/test/sql-tap/subquery.test.lua
+++ b/test/sql-tap/subquery.test.lua
@@ -287,7 +287,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "subquery-2.3.2",
     [[
-        SELECT a IN (10.0, 20) FROM t3;
+        SELECT a IN ('10.0', '20') FROM t3;
     ]], {
         -- <subquery-2.3.2>
         false
diff --git a/test/sql-tap/tkt-9a8b09f8e6.test.lua b/test/sql-tap/tkt-9a8b09f8e6.test.lua
index db0881c..a307649 100755
--- a/test/sql-tap/tkt-9a8b09f8e6.test.lua
+++ b/test/sql-tap/tkt-9a8b09f8e6.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(49)
+test:plan(48)
 
 --!./tcltestrunner.lua
 -- 2014 June 26
@@ -86,7 +86,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     2.1,
     [[
-        SELECT x FROM t1 WHERE x IN (1);
+        SELECT x FROM t1 WHERE x IN ('1');
     ]], {
         -- <2.1>
         "1"
@@ -96,7 +96,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     2.2,
     [[
-        SELECT x FROM t1 WHERE x IN (1.0);
+        SELECT x FROM t1 WHERE CAST(x AS NUMBER) IN (1.0);
     ]], {
         -- <2.2>
         "1"
@@ -126,7 +126,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     2.5,
     [[
-        SELECT x FROM t1 WHERE 1 IN (x);
+        SELECT x FROM t1 WHERE '1' IN (x);
     ]], {
         -- <2.5>
         "1"
@@ -136,7 +136,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     2.6,
     [[
-        SELECT x FROM t1 WHERE 1.0 IN (x);
+        SELECT x FROM t1 WHERE 1.0 IN (CAST(x AS NUMBER));
     ]], {
         -- <2.6>
         "1"
@@ -466,7 +466,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     6.3,
     [[
-        SELECT x, y FROM t5 WHERE x IN ('1');
+        SELECT x, y FROM t5 WHERE CAST(x AS STRING) IN ('1');
     ]], {
         -- <6.3>
         1, "one", 1, "two", 1, "three", 1.0, "four"
@@ -476,7 +476,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     6.4,
     [[
-        SELECT x, y FROM t5 WHERE x IN ('1.0');
+        SELECT x, y FROM t5 WHERE x IN (CAST('1.0' AS NUMBER));
     ]], {
         -- <6.4>
         1, "one", 1, "two", 1, "three", 1.0, "four"
@@ -506,23 +506,12 @@ test:do_execsql_test(
 test:do_execsql_test(
     6.7,
     [[
-        SELECT x, y FROM t5 WHERE '1' IN (x);
+        SELECT x, y FROM t5 WHERE '1' IN (CAST(x AS STRING));
     ]], {
         -- <6.7>
         1, "one", 1, "two", 1, "three", 1.0, "four"
         -- </6.7>
     })
 
-test:do_execsql_test(
-    6.8,
-    [[
-        SELECT x, y FROM t5 WHERE '1.0' IN (x);
-    ]], {
-        -- <6.8>
-        1, "one", 1, "two", 1, "three", 1, "four"
-        -- </6.8>
-    })
-
-
 
 test:finish_test()
diff --git a/test/sql-tap/tkt-f973c7ac31.test.lua b/test/sql-tap/tkt-f973c7ac31.test.lua
index 82bdb52..e38e099 100755
--- a/test/sql-tap/tkt-f973c7ac31.test.lua
+++ b/test/sql-tap/tkt-f973c7ac31.test.lua
@@ -39,7 +39,7 @@ for tn, sql in ipairs(sqls) do
     test:do_execsql_test(
         "tkt-f973c7ac3-1."..tn..".1",
         [[
-            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND c2<='2' ORDER BY c2 DESC 
+            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND c2<=2 ORDER BY c2 DESC
         ]], {
             
         })
@@ -55,7 +55,7 @@ for tn, sql in ipairs(sqls) do
     test:do_execsql_test(
         "tkt-f973c7ac3-1."..tn..".3",
         [[
-            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND c2<='5' ORDER BY c2 DESC 
+            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND CAST(c2 AS STRING)<='5' ORDER BY c2 DESC
         ]], {
             5, 5, 5, 4
         })
@@ -63,7 +63,7 @@ for tn, sql in ipairs(sqls) do
     test:do_execsql_test(
         "tkt-f973c7ac3-1."..tn..".4",
         [[
-            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>'0' AND c2<=5 ORDER BY c2 DESC 
+            SELECT c1,c2 FROM t WHERE c1 = 5 AND CAST(c2 AS STRING)>'0' AND c2<=5 ORDER BY c2 DESC
         ]], {
             5, 5, 5, 4
         })
@@ -71,7 +71,7 @@ for tn, sql in ipairs(sqls) do
     test:do_execsql_test(
         "tkt-f973c7ac3-1."..tn..".5",
         [[
-            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>'0' AND c2<='5' ORDER BY c2 DESC 
+            SELECT c1,c2 FROM t WHERE c1 = 5 AND CAST(c2 AS STRING)>'0' AND CAST(c2 AS STRING)<='5' ORDER BY c2 DESC 
         ]], {
             5, 5, 5, 4
         })
@@ -79,7 +79,7 @@ for tn, sql in ipairs(sqls) do
     test:do_execsql_test(
         "tkt-f973c7ac3-1."..tn..".6",
         [[
-            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND c2<='2' ORDER BY c2 ASC 
+            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND CAST(c2 AS STRING)<='2' ORDER BY c2 ASC 
         ]], {
             
         })
@@ -95,7 +95,7 @@ for tn, sql in ipairs(sqls) do
     test:do_execsql_test(
         "tkt-f973c7ac3-1."..tn..".8",
         [[
-            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND c2<='5' ORDER BY c2 ASC 
+            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>0 AND CAST(c2 AS STRING)<='5' ORDER BY c2 ASC 
         ]], {
             5, 4, 5, 5
         })
@@ -103,7 +103,7 @@ for tn, sql in ipairs(sqls) do
     test:do_execsql_test(
         "tkt-f973c7ac3-1."..tn..".9",
         [[
-            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>'0' AND c2<=5 ORDER BY c2 ASC 
+            SELECT c1,c2 FROM t WHERE c1 = 5 AND CAST(c2 AS STRING)>'0' AND c2<=5 ORDER BY c2 ASC 
         ]], {
             5, 4, 5, 5
         })
@@ -111,7 +111,7 @@ for tn, sql in ipairs(sqls) do
     test:do_execsql_test(
         "tkt-f973c7ac3-1."..tn..".10",
         [[
-            SELECT c1,c2 FROM t WHERE c1 = 5 AND c2>'0' AND c2<='5' ORDER BY c2 ASC 
+            SELECT c1,c2 FROM t WHERE c1 = 5 AND CAST(c2 AS STRING)>'0' AND CAST(c2 AS STRING)<='5' ORDER BY c2 ASC 
         ]], {
             5, 4, 5, 5
         })
diff --git a/test/sql-tap/tkt-fc7bd6358f.test.lua b/test/sql-tap/tkt-fc7bd6358f.test.lua
index fe5d620..f27f441 100755
--- a/test/sql-tap/tkt-fc7bd6358f.test.lua
+++ b/test/sql-tap/tkt-fc7bd6358f.test.lua
@@ -64,14 +64,14 @@ local froms = {
     "FROM t t1, t t2, i",
 }
 local wheres = {
-    "WHERE t1.textid=i.intid AND t1.textid=t2.textid",
-    "WHERE i.intid=t1.textid AND t1.textid=t2.textid",
-    "WHERE t1.textid=i.intid AND i.intid=t2.textid",
-    "WHERE t1.textid=i.intid AND t2.textid=i.intid",
-    "WHERE i.intid=t1.textid AND i.intid=t2.textid",
-    "WHERE i.intid=t1.textid AND t2.textid=i.intid",
-    "WHERE t1.textid=t2.textid AND i.intid=t2.textid",
-    "WHERE t1.textid=t2.textid AND t2.textid=i.intid",
+    "WHERE CAST(t1.textid AS INTEGER)=i.intid AND t1.textid=t2.textid",
+    "WHERE i.intid=CAST(t1.textid AS INTEGER) AND t1.textid=t2.textid",
+    "WHERE CAST(t1.textid AS INTEGER)=i.intid AND i.intid=CAST(t2.textid AS INTEGER)",
+    "WHERE CAST(t1.textid AS INTEGER)=i.intid AND CAST(t2.textid AS INTEGER)=i.intid",
+    "WHERE i.intid=CAST(t1.textid AS INTEGER) AND i.intid=CAST(t2.textid AS INTEGER)",
+    "WHERE i.intid=CAST(t1.textid AS INTEGER) AND CAST(t2.textid AS INTEGER)=i.intid",
+    "WHERE t1.textid=t2.textid AND i.intid=CAST(t2.textid AS INTEGER)",
+    "WHERE t1.textid=t2.textid AND CAST(t2.textid AS INTEGER)=i.intid",
 }
 for a, from in ipairs(froms) do
     for b, where in ipairs(wheres) do
diff --git a/test/sql-tap/tkt3493.test.lua b/test/sql-tap/tkt3493.test.lua
index 7ceec47..768282a 100755
--- a/test/sql-tap/tkt3493.test.lua
+++ b/test/sql-tap/tkt3493.test.lua
@@ -45,7 +45,7 @@ test:do_execsql_test(
     [[
         SELECT 
           CASE 
-             WHEN B.val = 1 THEN 'XYZ' 
+             WHEN B.val = '1' THEN 'XYZ'
              ELSE A.val 
           END AS Col1
         FROM B  
@@ -63,7 +63,7 @@ test:do_execsql_test(
     [[
         SELECT DISTINCT
           CASE 
-             WHEN B.val = 1 THEN 'XYZ' 
+             WHEN B.val = '1' THEN 'XYZ'
              ELSE A.val 
           END AS Col1
         FROM B  
@@ -79,7 +79,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-1.4",
     [[
-        SELECT b.val, CASE WHEN b.val = 1 THEN 'xyz' ELSE b.val END AS col1 FROM b;
+        SELECT b.val, CASE WHEN b.val = '1' THEN 'xyz' ELSE b.val END AS col1 FROM b;
     ]], {
         -- <tkt3493-1.4>
         "1", "xyz", "2", "2"
@@ -91,7 +91,7 @@ test:do_execsql_test(
     [[
         SELECT DISTINCT 
           b.val, 
-          CASE WHEN b.val = 1 THEN 'xyz' ELSE b.val END AS col1 
+          CASE WHEN b.val = '1' THEN 'xyz' ELSE b.val END AS col1
         FROM b;
     ]], {
         -- <tkt3493-1.5>
@@ -104,7 +104,7 @@ test:do_execsql_test(
     [[
         SELECT DISTINCT 
           b.val, 
-          CASE WHEN b.val = '1' THEN 'xyz' ELSE b.val END AS col1 
+          CASE WHEN b.val = '1' THEN 'xyz' ELSE b.val END AS col1
         FROM b;
     ]], {
         -- <tkt3493-1.6>
@@ -126,7 +126,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.2.1",
     [[
-        SELECT a=123 FROM t1 GROUP BY a 
+        SELECT CAST(a AS NUMBER) = 123 FROM t1 GROUP BY a
     ]], {
         -- <tkt3493-2.2.1>
         true
@@ -136,7 +136,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.2.2",
     [[
-        SELECT a=123 FROM t1 
+        SELECT CAST(a AS NUMBER) = 123 FROM t1
     ]], {
         -- <tkt3493-2.2.2>
         true
@@ -156,7 +156,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.2.4",
     [[
-        SELECT count(*), a=123 FROM t1 
+        SELECT count(*), a='123' FROM t1
     ]], {
         -- <tkt3493-2.2.4>
         1, true
@@ -166,7 +166,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.2.5",
     [[
-        SELECT count(*), +a=123 FROM t1 
+        SELECT count(*), +a='123' FROM t1
     ]], {
         -- <tkt3493-2.2.5>
         1, true
@@ -176,7 +176,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.3.3",
     [[
-        SELECT b='456' FROM t1 GROUP BY a 
+        SELECT b=456 FROM t1 GROUP BY a
     ]], {
         -- <tkt3493-2.3.3>
         true
@@ -186,7 +186,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.3.1",
     [[
-        SELECT b='456' FROM t1 GROUP BY b 
+        SELECT b=456 FROM t1 GROUP BY b
     ]], {
         -- <tkt3493-2.3.1>
         true
@@ -196,7 +196,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.3.2",
     [[
-        SELECT b='456' FROM t1 
+        SELECT b=456 FROM t1
     ]], {
         -- <tkt3493-2.3.2>
         true
@@ -206,7 +206,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.4.1",
     [[
-        SELECT typeof(a), a FROM t1 GROUP BY a HAVING a=123 
+        SELECT typeof(a), a FROM t1 GROUP BY a HAVING a='123'
     ]], {
         -- <tkt3493-2.4.1>
         "string", "123"
@@ -216,7 +216,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.4.2",
     [[
-        SELECT typeof(a), a FROM t1 GROUP BY b HAVING a=123 
+        SELECT typeof(a), a FROM t1 GROUP BY b HAVING a='123'
     ]], {
         -- <tkt3493-2.4.2>
         "string", "123"
@@ -226,7 +226,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.5.1",
     [[
-        SELECT typeof(b), b FROM t1 GROUP BY a HAVING b='456' 
+        SELECT typeof(b), b FROM t1 GROUP BY a HAVING b=456
     ]], {
         -- <tkt3493-2.5.1>
         "integer", 456
@@ -236,7 +236,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "tkt3493-2.5.2",
     [[
-        SELECT typeof(b), b FROM t1 GROUP BY b HAVING b='456' 
+        SELECT typeof(b), b FROM t1 GROUP BY b HAVING b=456
     ]], {
         -- <tkt3493-2.5.2>
         "integer", 456
diff --git a/test/sql-tap/transitive1.test.lua b/test/sql-tap/transitive1.test.lua
index e960565..1cc6d11 100755
--- a/test/sql-tap/transitive1.test.lua
+++ b/test/sql-tap/transitive1.test.lua
@@ -63,7 +63,7 @@ test:do_execsql_test(
         INSERT INTO t2 VALUES(2, 20,20,'20');
         INSERT INTO t2 VALUES(3, 3,3,'3');
 
-        SELECT a,b,c FROM t2 WHERE a=b AND c=b AND c=20;
+        SELECT a,b,c FROM t2 WHERE a=b AND CAST(c AS INTEGER)=b AND c='20';
     ]], {
         -- <transitive1-200>
         20, 20, "20"
@@ -73,7 +73,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "transitive1-210",
     [[
-        SELECT a,b,c FROM t2 WHERE a=b AND c=b AND c>='20' ORDER BY +a;
+        SELECT a,b,c FROM t2 WHERE a=b AND CAST(c AS INTEGER)=b AND c>='20' ORDER BY +a;
     ]], {
         -- <transitive1-210>
         3, 3, "3", 20, 20, "20"
@@ -83,7 +83,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "transitive1-220",
     [[
-        SELECT a,b,c FROM t2 WHERE a=b AND c=b AND c<='20' ORDER BY +a;
+        SELECT a,b,c FROM t2 WHERE a=b AND CAST(c AS INTEGER)=b AND c<='20' ORDER BY +a;
     ]], {
         -- <transitive1-220>
         20, 20, "20", 100, 100, "100"
@@ -402,7 +402,7 @@ test:do_execsql_test(
     [[
         CREATE TABLE x(i INTEGER PRIMARY KEY, y TEXT);
         INSERT INTO x VALUES(10, '10');
-        SELECT * FROM x WHERE x.y>='1' AND x.y<'2' AND x.i=x.y;
+        SELECT * FROM x WHERE x.y>='1' AND x.y<'2' AND x.i=CAST(x.y AS NUMBER);
     ]], {
         -- <transitive1-500>
         10, "10"
@@ -430,7 +430,7 @@ test:do_execsql_test(
     [[
         CREATE TABLE t3(i INTEGER PRIMARY KEY, t TEXT);
         INSERT INTO t3 VALUES(10, '10');
-        SELECT * FROM t3 WHERE i=t AND t = '10 ';
+        SELECT * FROM t3 WHERE CAST(i AS STRING)=t AND t = '10 ';
     ]], {
         -- <transitive1-520>
 
@@ -443,7 +443,7 @@ test:do_execsql_test(
         CREATE TABLE u1(x TEXT PRIMARY KEY, y INTEGER, z TEXT);
         CREATE INDEX i1 ON u1(x);
         INSERT INTO u1 VALUES('00013', 13, '013');
-        SELECT * FROM u1 WHERE x=y AND y=z AND z='013';
+        SELECT * FROM u1 WHERE CAST(x AS NUMBER)=y AND y=CAST(z AS NUMBER) AND z='013';
     ]], {
         -- <transitive1-530>
         "00013",13,"013"
diff --git a/test/sql-tap/where2.test.lua b/test/sql-tap/where2.test.lua
index f267be8..747fa32 100755
--- a/test/sql-tap/where2.test.lua
+++ b/test/sql-tap/where2.test.lua
@@ -637,11 +637,7 @@ test:do_test(
                 INSERT INTO t2249b VALUES(123);
             ]]
             return queryplan([[
-    -- Because a is type TEXT and b is type INTEGER, both a and b
-    -- will attempt to convert to NUMERIC before the comparison.
-    -- They will thus compare equal.
-    --
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=b;
+    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE CAST(a AS NUMBER)=b;
   ]])
         end, {
             -- <where2-6.7>
@@ -653,9 +649,7 @@ test:do_test(
         "where2-6.9",
         function()
             return queryplan([[
-    -- The + operator doesn't affect RHS.
-    --
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=+b;
+    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE CAST(a AS NUMBER)=+b;
   ]])
         end, {
             -- <where2-6.9>
@@ -668,7 +662,7 @@ test:do_test(
         function()
             -- The same thing but with the expression flipped around.
             return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +b=a
+    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +b=CAST(a AS NUMBER)
   ]])
         end, {
             -- <where2-6.9.2>
@@ -680,7 +674,7 @@ test:do_test(
         "where2-6.10",
         function()
             return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +a=+b;
+    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +CAST(a AS NUMBER)=+b;
   ]])
         end, {
             -- <where2-6.10>
@@ -694,7 +688,7 @@ test:do_test(
             -- This will not attempt the OR optimization because of the a=b
             -- comparison.
             return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=b OR a='hello';
+    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE CAST(a AS NUMBER)=b OR a='hello';
   ]])
         end, {
             -- <where2-6.11>
@@ -707,7 +701,7 @@ test:do_test(
         function()
             -- Permutations of the expression terms.
             return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE b=a OR a='hello';
+    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE b=CAST(a AS NUMBER) OR a='hello';
   ]])
         end, {
             -- <where2-6.11.2>
@@ -720,7 +714,7 @@ test:do_test(
         function()
             -- Permutations of the expression terms.
             return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE 'hello'=a OR b=a;
+    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE 'hello'=a OR b=CAST(a AS NUMBER);
   ]])
         end, {
             -- <where2-6.11.3>
@@ -733,7 +727,7 @@ test:do_test(
         function()
             -- Permutations of the expression terms.
             return queryplan([[
-    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR b=a;
+    SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR b=CAST(a AS NUMBER);
   ]])
         end, {
             -- <where2-6.11.4>
@@ -750,7 +744,7 @@ test:do_test(
         "where2-6.12",
         function()
             return queryplan([[
-      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=+b OR a='hello';
+      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE CAST(a AS NUMBER)=+b OR a='hello';
     ]])
         end, {
             -- <where2-6.12>
@@ -762,7 +756,7 @@ test:do_test(
         "where2-6.12.2",
         function()
             return queryplan([[
-      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR +b=a;
+      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a='hello' OR +b=CAST(a AS NUMBER);
     ]])
         end, {
             -- <where2-6.12.2>
@@ -774,7 +768,7 @@ test:do_test(
         "where2-6.12.3",
         function()
             return queryplan([[
-      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +b=a OR a='hello';
+      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE +b=CAST(a AS NUMBER) OR a='hello';
     ]])
         end, {
             -- <where2-6.12.3>
@@ -788,7 +782,7 @@ test:do_test(
             -- The addition of +a on the second term disabled the OR optimization.
             -- But we should still get the same empty-set result as in where2-6.9.
             return queryplan([[
-      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE a=+b OR +a='hello';
+      SELECT b,a FROM t2249b CROSS JOIN t2249a WHERE CAST(a AS NUMBER)=+b OR +a='hello';
     ]])
         end, {
             -- <where2-6.13>
diff --git a/test/sql-tap/where5.test.lua b/test/sql-tap/where5.test.lua
index 7492015..3bda68e 100755
--- a/test/sql-tap/where5.test.lua
+++ b/test/sql-tap/where5.test.lua
@@ -34,7 +34,7 @@ test:do_test("where5-1.0", function()
         INSERT INTO t3 SELECT * FROM t1;
     ]]
     return test:execsql [[
-        SELECT * FROM t1 WHERE x<0
+        SELECT * FROM t1 WHERE CAST(x AS NUMBER)<0
     ]]
 end, {
     -- <where5-1.0>
@@ -43,7 +43,7 @@ end, {
 })
 
 test:do_execsql_test("where5-1.1", [[
-    SELECT * FROM t1 WHERE x<=0
+    SELECT * FROM t1 WHERE CAST(x AS NUMBER)<=0
 ]], {
     -- <where5-1.1>
     '-1', '0'
@@ -51,7 +51,7 @@ test:do_execsql_test("where5-1.1", [[
 })
 
 test:do_execsql_test("where5-1.2", [[
-    SELECT * FROM t1 WHERE x=0
+    SELECT * FROM t1 WHERE CAST(x AS NUMBER)=0
 ]], {
     -- <where5-1.2>
     '0'
@@ -59,7 +59,7 @@ test:do_execsql_test("where5-1.2", [[
 })
 
 test:do_execsql_test("where5-1.3", [[
-    SELECT * FROM t1 WHERE x>=0
+    SELECT * FROM t1 WHERE CAST(x AS NUMBER)>=0
 ]], {
     -- <where5-1.3>
     '0', '1'
@@ -67,7 +67,7 @@ test:do_execsql_test("where5-1.3", [[
 })
 
 test:do_execsql_test("where5-1.4", [[
-    SELECT * FROM t1 WHERE x>0
+    SELECT * FROM t1 WHERE CAST(x AS NUMBER)>0
 ]], {
     -- <where5-1.4>
     '1'
@@ -75,7 +75,7 @@ test:do_execsql_test("where5-1.4", [[
 })
 
 test:do_execsql_test("where5-1.5", [[
-    SELECT * FROM t1 WHERE x<>0
+    SELECT * FROM t1 WHERE CAST(x AS NUMBER)<>0
 ]], {
     -- <where5-1.5>
     '-1', '1'
diff --git a/test/sql-tap/whereB.test.lua b/test/sql-tap/whereB.test.lua
index d98645f..1f6dd97 100755
--- a/test/sql-tap/whereB.test.lua
+++ b/test/sql-tap/whereB.test.lua
@@ -37,7 +37,7 @@ test:do_execsql_test(
         CREATE INDEX t2b ON t2(b);
         INSERT INTO t2 VALUES(2,'99');
 
-        SELECT x, a, y=b FROM t1, t2 ORDER BY +x, +a;
+        SELECT x, a, y=CAST(b AS NUMBER) FROM t1, t2 ORDER BY +x, +a;
     ]],
     {
     -- <whereB-1.1>
@@ -48,7 +48,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "whereB-1.2",
     [[
-        SELECT x, a, y=b FROM t1, t2 WHERE y=b;
+        SELECT x, a, y=CAST(b AS NUMBER) FROM t1, t2 WHERE y=CAST(b AS NUMBER);
     ]],
     {
     -- <whereB-1.2>
@@ -59,7 +59,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "whereB-1.3",
     [[
-        SELECT x, a, y=b FROM t1, t2 WHERE b=y;
+        SELECT x, a, y=CAST(b AS NUMBER) FROM t1, t2 WHERE CAST(b AS NUMBER)=y;
     ]],
     {
     -- <whereB-1.3>
@@ -70,7 +70,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "whereB-1.4",
     [[
-        SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
+        SELECT x, a, y=CAST(b AS NUMBER) FROM t1, t2 WHERE +y=+CAST(b AS NUMBER);
     ]],
     {
     -- <whereB-1.4>
@@ -82,7 +82,7 @@ test:do_execsql_test(
     "whereB-1.100",
     [[
         DROP INDEX t2b ON t2;
-        SELECT x, a, y=b FROM t1, t2 WHERE y=b;
+        SELECT x, a, y=CAST(b AS NUMBER) FROM t1, t2 WHERE y=CAST(b AS NUMBER);
     ]],
     {
     -- <whereB-1.100>
@@ -93,7 +93,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "whereB-1.101",
     [[
-        SELECT x, a, y=b FROM t1, t2 WHERE b=y;
+        SELECT x, a, y=CAST(b AS NUMBER) FROM t1, t2 WHERE CAST(b AS NUMBER)=y;
     ]],
     {
     -- <whereB-1.101>
@@ -104,7 +104,7 @@ test:do_execsql_test(
 test:do_execsql_test(
     "whereB-1.102",
     [[
-        SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
+        SELECT x, a, y=CAST(b AS NUMBER) FROM t1, t2 WHERE +y=+CAST(b AS NUMBER);
     ]],
     {
     -- <whereB-1.102>
@@ -120,7 +120,7 @@ test:do_execsql_test(
 -- These values are not equal and because neither affinity is NUMERIC
 -- no type conversion occurs.
 --
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-2.1",
     [[
         DROP TABLE t1;
@@ -137,7 +137,7 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-2.1>
-    1, 2, false
+    1, "Type mismatch: can not convert unsigned to text"
     -- </whereB-2.1>
     })
 
@@ -163,18 +163,18 @@ test:do_execsql_test(
     -- </whereB-2.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-2.4",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
     ]],
     {
     -- <whereB-2.4>
-    
+    1, "Type mismatch: can not convert unsigned to text"
     -- </whereB-2.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-2.100",
     [[
         DROP INDEX t2b ON t2;
@@ -182,29 +182,29 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-2.100>
-    
+    1, "Type mismatch: can not convert unsigned to text"
     -- </whereB-2.100>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-2.101",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-2.101>
-    
+    1, "Type mismatch: can not convert text to unsigned"
     -- </whereB-2.101>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-2.102",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
     ]],
     {
     -- <whereB-2.102>
-    
+    1, "Type mismatch: can not convert unsigned to text"
     -- </whereB-2.102>
     })
 
@@ -216,7 +216,7 @@ test:do_execsql_test(
 -- These values are not equal and because neither affinity is NUMERIC
 -- no type conversion occurs.
 --
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-3.1",
     [[
         DROP TABLE t1;
@@ -233,7 +233,7 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-3.1>
-    1, 2, false
+    1, "Type mismatch: can not convert text to unsigned"
     -- </whereB-3.1>
     })
 
@@ -259,18 +259,18 @@ test:do_execsql_test(
     -- </whereB-3.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-3.4",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
     ]],
     {
     -- <whereB-3.4>
-    
+    1, "Type mismatch: can not convert text to unsigned"
     -- </whereB-3.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-3.100",
     [[
         DROP INDEX t2b ON t2;
@@ -278,29 +278,29 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-3.100>
-    
+    1, "Type mismatch: can not convert text to unsigned"
     -- </whereB-3.100>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-3.101",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-3.101>
-    
+    1, "Type mismatch: can not convert unsigned to text"
     -- </whereB-3.101>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-3.102",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE +y=+b;
     ]],
     {
     -- <whereB-3.102>
-    
+    1, "Type mismatch: can not convert text to unsigned"
     -- </whereB-3.102>
     })
 
@@ -312,7 +312,7 @@ test:do_execsql_test(
 -- Because t2.b has a numeric affinity, type conversion should occur
 -- and the two fields should be equal.
 --
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-4.1",
     [[
         DROP TABLE IF EXISTS t1;
@@ -329,33 +329,33 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-4.1>
-    1, 2, true
+    1, "Type mismatch: can not convert unsigned to text"
     -- </whereB-4.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-4.2",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE y=b;
     ]],
     {
     -- <whereB-4.2>
-    1, 2, true
+    1, "Type mismatch: can not convert unsigned to text"
     -- </whereB-4.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-4.3",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-4.3>
-    1, 2, true
+    1, "Type mismatch: can not convert unsigned to text"
     -- </whereB-4.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-4.4",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -364,11 +364,11 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-4.4>
-    1, 2, true
+    1, "Type mismatch: can not convert unsigned to text"
     -- </whereB-4.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-4.100",
     [[
         DROP INDEX t2b ON t2;
@@ -376,22 +376,22 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-4.100>
-    1, 2, true
+    1, "Type mismatch: can not convert unsigned to text"
     -- </whereB-4.100>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-4.101",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-4.101>
-    1, 2, true
+    1, "Type mismatch: can not convert text to unsigned"
     -- </whereB-4.101>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-4.102",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -400,7 +400,7 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-4.102>
-    1, 2, true
+    1, "Type mismatch: can not convert unsigned to text"
     -- </whereB-4.102>
     })
 
@@ -412,7 +412,7 @@ test:do_execsql_test(
 -- Because t2.b has a numeric affinity, type conversion should occur
 -- and the two fields should be equal.
 --
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-5.1",
     [[
         DROP TABLE t1;
@@ -429,33 +429,33 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-5.1>
-    1, 2, true
+    1, "Type mismatch: can not convert unsigned to text"
     -- </whereB-5.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-5.2",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE y=b;
     ]],
     {
     -- <whereB-5.2>
-    1, 2, true
+    1, "Type mismatch: can not convert unsigned to text"
     -- </whereB-5.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-5.3",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-5.3>
-    1, 2, true
+    1, "Type mismatch: can not convert unsigned to text"
     -- </whereB-5.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-5.4",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -464,11 +464,11 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-5.4>
-    1, 2, true
+    1, "Type mismatch: can not convert unsigned to text"
     -- </whereB-5.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-5.100",
     [[
         DROP INDEX t2b ON t2;
@@ -476,22 +476,22 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-5.100>
-    1, 2, true
+    1, "Type mismatch: can not convert unsigned to text"
     -- </whereB-5.100>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-5.101",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-5.101>
-    1, 2, true
+    1, "Type mismatch: can not convert text to unsigned"
     -- </whereB-5.101>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-5.102",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -500,7 +500,7 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-5.102>
-    1, 2, true
+    1, "Type mismatch: can not convert unsigned to text"
     -- </whereB-5.102>
     })
 
@@ -512,7 +512,7 @@ test:do_execsql_test(
 -- Because t2.b has a numeric affinity, type conversion should occur
 -- and the two fields should be equal.
 --
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-6.1",
     [[
         DROP TABLE t1;
@@ -529,33 +529,33 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-6.1>
-    1, 2, true
+    1, "Type mismatch: can not convert real to text"
     -- </whereB-6.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-6.2",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE y=b;
     ]],
     {
     -- <whereB-6.2>
-    1, 2, true
+    1, "Type mismatch: can not convert real to text"
     -- </whereB-6.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-6.3",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-6.3>
-    1, 2, true
+    1, "Type mismatch: can not convert real to text"
     -- </whereB-6.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-6.4",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -564,11 +564,11 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-6.4>
-    1, 2, true
+    1, "Type mismatch: can not convert real to text"
     -- </whereB-6.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-6.100",
     [[
         DROP INDEX t2b ON t2;
@@ -576,22 +576,22 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-6.100>
-    1, 2, true
+    1, "Type mismatch: can not convert real to text"
     -- </whereB-6.100>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-6.101",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-6.101>
-    1, 2, true
+    1, "Type mismatch: can not convert text to real"
     -- </whereB-6.101>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-6.102",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -600,7 +600,7 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-6.102>
-    1, 2, true
+    1, "Type mismatch: can not convert real to text"
     -- </whereB-6.102>
     })
 
@@ -612,7 +612,7 @@ test:do_execsql_test(
 -- Because t1.y has a numeric affinity, type conversion should occur
 -- and the two fields should be equal.
 --
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-7.1",
     [[
         DROP TABLE t1;
@@ -629,33 +629,33 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-7.1>
-    1, 2, true
+    1, "Type mismatch: can not convert text to unsigned"
     -- </whereB-7.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-7.2",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE y=b;
     ]],
     {
     -- <whereB-7.2>
-    1, 2, true
+    1, "Type mismatch: can not convert text to unsigned"
     -- </whereB-7.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-7.3",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-7.3>
-    1, 2, true
+    1, "Type mismatch: can not convert unsigned to text"
     -- </whereB-7.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-7.4",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -664,11 +664,11 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-7.4>
-    1, 2, true
+    1, "Type mismatch: can not convert text to unsigned"
     -- </whereB-7.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-7.100",
     [[
         DROP INDEX t2b ON t2;
@@ -676,22 +676,22 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-7.100>
-    1, 2, true
+    1, "Type mismatch: can not convert text to unsigned"
     -- </whereB-7.100>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-7.101",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-7.101>
-    1, 2, true
+    1, "Type mismatch: can not convert unsigned to text"
     -- </whereB-7.101>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-7.102",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -700,7 +700,7 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-7.102>
-    1, 2, true
+    1, "Type mismatch: can not convert text to unsigned"
     -- </whereB-7.102>
     })
 
@@ -712,7 +712,7 @@ test:do_execsql_test(
 -- Because t1.y has a numeric affinity, type conversion should occur
 -- and the two fields should be equal.
 --
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-8.1",
     [[
         DROP TABLE t1;
@@ -729,33 +729,33 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-8.1>
-    1, 2, true
+    1, "Type mismatch: can not convert text to unsigned"
     -- </whereB-8.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-8.2",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE y=b;
     ]],
     {
     -- <whereB-8.2>
-    1, 2, true
+    1, "Type mismatch: can not convert text to unsigned"
     -- </whereB-8.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-8.3",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-8.3>
-    1, 2, true
+    1, "Type mismatch: can not convert unsigned to text"
     -- </whereB-8.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-8.4",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -764,11 +764,11 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-8.4>
-    1, 2, true
+    1, "Type mismatch: can not convert text to unsigned"
     -- </whereB-8.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-8.100",
     [[
         DROP INDEX t2b ON t2;
@@ -776,22 +776,22 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-8.100>
-    1, 2, true
+    1, "Type mismatch: can not convert text to unsigned"
     -- </whereB-8.100>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-8.101",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-8.101>
-    1, 2, true
+    1, "Type mismatch: can not convert unsigned to text"
     -- </whereB-8.101>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-8.102",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -800,7 +800,7 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-8.102>
-    1, 2, true
+    1, "Type mismatch: can not convert text to unsigned"
     -- </whereB-8.102>
     })
 
@@ -812,7 +812,7 @@ test:do_execsql_test(
 -- Because t1.y has a numeric affinity, type conversion should occur
 -- and the two fields should be equal.
 --
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-9.1",
     [[
         DROP TABLE t1;
@@ -829,33 +829,33 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-9.1>
-    1, 2, true
+    1, "Type mismatch: can not convert text to real"
     -- </whereB-9.1>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-9.2",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE y=b;
     ]],
     {
     -- <whereB-9.2>
-    1, 2, true
+    1, "Type mismatch: can not convert text to real"
     -- </whereB-9.2>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-9.3",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-9.3>
-    1, 2, true
+    1, "Type mismatch: can not convert real to text"
     -- </whereB-9.3>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-9.4",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -864,11 +864,11 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-9.4>
-    1, 2, true
+    1, "Type mismatch: can not convert text to real"
     -- </whereB-9.4>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-9.100",
     [[
         DROP INDEX t2b ON t2;
@@ -876,22 +876,22 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-9.100>
-    1, 2, true
+    1, "Type mismatch: can not convert text to real"
     -- </whereB-9.100>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-9.101",
     [[
         SELECT x, a, y=b FROM t1, t2 WHERE b=y;
     ]],
     {
     -- <whereB-9.101>
-    1, 2, true
+    1, "Type mismatch: can not convert real to text"
     -- </whereB-9.101>
     })
 
-test:do_execsql_test(
+test:do_catchsql_test(
     "whereB-9.102",
     -- In this case the unary "+" operator shouldn't
     -- affect result set of query.
@@ -900,7 +900,7 @@ test:do_execsql_test(
     ]],
     {
     -- <whereB-9.102>
-    1, 2, true
+    1, "Type mismatch: can not convert text to real"
     -- </whereB-9.102>
     })
 
diff --git a/test/sql-tap/whereC.test.lua b/test/sql-tap/whereC.test.lua
index 89459de..58c0495 100755
--- a/test/sql-tap/whereC.test.lua
+++ b/test/sql-tap/whereC.test.lua
@@ -55,9 +55,9 @@ test:do_execsql_test(
 test:test("main", function()
     local data = {{"SELECT i FROM t1 WHERE a=1 AND b=2 AND i>3",         {4, 5}},
                   -- {"SELECT i FROM t1 WHERE rowid='12'",                  {12}},
-                  {"SELECT i FROM t1 WHERE a=1 AND b='2'",               {3, 4, 5}},
-                  {"SELECT i FROM t1 WHERE a=1 AND b='2' AND i>'3'",     {4, 5}},
-                  {"SELECT i FROM t1 WHERE a=1 AND b='2' AND i<5",       {3, 4}},
+                  {"SELECT i FROM t1 WHERE a=1 AND b=2",               {3, 4, 5}},
+                  {"SELECT i FROM t1 WHERE a=1 AND b=2 AND i>3",     {4, 5}},
+                  {"SELECT i FROM t1 WHERE a=1 AND b=2 AND i<5",       {3, 4}},
                   {"SELECT i FROM t1 WHERE a=2 AND b=2 AND i<12",        {10, 11}},
                   {"SELECT i FROM t1 WHERE a IN(1, 2) AND b=2 AND i<11", {3, 4, 5, 10}},
                   {"SELECT i FROM t1 WHERE a=2 AND b=2 AND i BETWEEN 10 AND 12", {10, 11, 12}},
@@ -66,7 +66,7 @@ test:test("main", function()
                   {"SELECT i FROM t1 WHERE a=2 AND b=2 AND i BETWEEN 12 AND 10", {}},
                   {"SELECT i FROM t1 WHERE a=2 AND b=2 AND i<NULL",      {}},
                   {"SELECT i FROM t1 WHERE a=2 AND b=2 AND i>=NULL",     {}},
-                  {"SELECT i FROM t1 WHERE a=1 AND b='2' AND i<4.5",     {3, 4}}}
+                  {"SELECT i FROM t1 WHERE a=1 AND b=2 AND i<4.5",     {3, 4}}}
                   -- {"SELECT i FROM t1 WHERE rowid IS '12'",               {12}}}
 
     for tn, t in ipairs(data) do
diff --git a/test/sql/boolean.result b/test/sql/boolean.result
index 112e41a..2506536 100644
--- a/test/sql/boolean.result
+++ b/test/sql/boolean.result
@@ -138,12 +138,12 @@ INSERT INTO ts(s) VALUES ('abc'), (12.5);
 SELECT s FROM ts WHERE s = true;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 SELECT s FROM ts WHERE s < true;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 SELECT s FROM ts WHERE s IN (true, 1, 'abcd');
  | ---
@@ -3389,22 +3389,22 @@ SELECT false < 2;
 SELECT 2 > true;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT 2 > false;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT 2 < true;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT 2 < false;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 
 SELECT a1, a1 > 2 FROM t6
@@ -3420,12 +3420,12 @@ SELECT a1, a1 < 2 FROM t6
 SELECT a1, 2 > a1 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a1, 2 < a1 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a2, a2 > 2 FROM t6
  | ---
@@ -3440,12 +3440,12 @@ SELECT a2, a2 < 2 FROM t6
 SELECT a2, 2 > a2 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a2, 2 < a2 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 
 SELECT b, true > b FROM t7;
@@ -3471,22 +3471,22 @@ SELECT b, false < b FROM t7;
 SELECT b, b > true FROM t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT b, b > false FROM t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT b, b < true FROM t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT b, b < false FROM t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 
 SELECT a1, b, a1 > b FROM t6, t7;
@@ -3502,12 +3502,12 @@ SELECT a1, b, a1 < b FROM t6, t7;
 SELECT a1, b, b > a1 FROM t6, t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a1, b, b < a1 FROM t6, t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a2, b, a2 > b FROM t6, t7;
  | ---
@@ -3522,12 +3522,12 @@ SELECT a2, b, a2 < b FROM t6, t7;
 SELECT a2, b, b > a2 FROM t6, t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a2, b, b < a2 FROM t6, t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 
 SELECT true >= 2;
@@ -3553,22 +3553,22 @@ SELECT false <= 2;
 SELECT 2 >= true;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT 2 >= false;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT 2 <= true;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT 2 <= false;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 
 SELECT a1, a1 >= 2 FROM t6
@@ -3584,12 +3584,12 @@ SELECT a1, a1 <= 2 FROM t6
 SELECT a1, 2 >= a1 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a1, 2 <= a1 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a2, a2 >= 2 FROM t6
  | ---
@@ -3604,12 +3604,12 @@ SELECT a2, a2 <= 2 FROM t6
 SELECT a2, 2 >= a2 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a2, 2 <= a2 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 
 SELECT b, true >= b FROM t7;
@@ -3635,22 +3635,22 @@ SELECT b, false <= b FROM t7;
 SELECT b, b >= true FROM t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT b, b >= false FROM t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT b, b <= true FROM t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT b, b <= false FROM t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 
 SELECT a1, b, a1 >= b FROM t6, t7;
@@ -3666,12 +3666,12 @@ SELECT a1, b, a1 <= b FROM t6, t7;
 SELECT a1, b, b >= a1 FROM t6, t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a1, b, b <= a1 FROM t6, t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a2, b, a2 >= b FROM t6, t7;
  | ---
@@ -3686,12 +3686,12 @@ SELECT a2, b, a2 <= b FROM t6, t7;
 SELECT a2, b, b >= a2 FROM t6, t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a2, b, b <= a2 FROM t6, t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 
 SELECT true == 2;
@@ -3717,22 +3717,22 @@ SELECT false != 2;
 SELECT 2 == true;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT 2 == false;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT 2 != true;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT 2 != false;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 
 SELECT a1, a1 == 2 FROM t6
@@ -3748,12 +3748,12 @@ SELECT a1, a1 != 2 FROM t6
 SELECT a1, 2 == a1 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a1, 2 != a1 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a2, a2 == 2 FROM t6
  | ---
@@ -3768,12 +3768,12 @@ SELECT a2, a2 != 2 FROM t6
 SELECT a2, 2 == a2 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a2, 2 != a2 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 
 SELECT b, true == b FROM t7;
@@ -3799,22 +3799,22 @@ SELECT b, false != b FROM t7;
 SELECT b, b == true FROM t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT b, b == false FROM t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT b, b != true FROM t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT b, b != false FROM t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 
 SELECT a1, b, a1 == b FROM t6, t7;
@@ -3830,12 +3830,12 @@ SELECT a1, b, a1 != b FROM t6, t7;
 SELECT a1, b, b == a1 FROM t6, t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a1, b, b != a1 FROM t6, t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a2, b, a2 == b FROM t6, t7;
  | ---
@@ -3850,12 +3850,12 @@ SELECT a2, b, a2 != b FROM t6, t7;
 SELECT a2, b, b == a2 FROM t6, t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 SELECT a2, b, b != a2 FROM t6, t7;
  | ---
  | - null
- | - 'Type mismatch: can not convert unsigned to boolean'
+ | - 'Type mismatch: can not convert boolean to unsigned'
  | ...
 
 SELECT true IN (0, 1, 2, 3);
@@ -4534,22 +4534,22 @@ SELECT false < 2.3;
 SELECT 2.3 > true;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT 2.3 > false;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT 2.3 < true;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT 2.3 < false;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 
 SELECT a1, a1 > 2.3 FROM t6
@@ -4565,12 +4565,12 @@ SELECT a1, a1 < 2.3 FROM t6
 SELECT a1, 2.3 > a1 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a1, 2.3 < a1 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a2, a2 > 2.3 FROM t6
  | ---
@@ -4585,12 +4585,12 @@ SELECT a2, a2 < 2.3 FROM t6
 SELECT a2, 2.3 > a2 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a2, 2.3 < a2 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 
 SELECT c, true > c FROM t8;
@@ -4616,22 +4616,22 @@ SELECT c, false < c FROM t8;
 SELECT c, c > true FROM t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT c, c > false FROM t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT c, c < true FROM t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT c, c < false FROM t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 
 SELECT a1, c, a1 > c FROM t6, t8;
@@ -4647,12 +4647,12 @@ SELECT a1, c, a1 < c FROM t6, t8;
 SELECT a1, c, c > a1 FROM t6, t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a1, c, c < a1 FROM t6, t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a2, c, a2 > c FROM t6, t8;
  | ---
@@ -4667,12 +4667,12 @@ SELECT a2, c, a2 < c FROM t6, t8;
 SELECT a2, c, c > a2 FROM t6, t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a2, c, c < a2 FROM t6, t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 
 SELECT true >= 2.3;
@@ -4698,22 +4698,22 @@ SELECT false <= 2.3;
 SELECT 2.3 >= true;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT 2.3 >= false;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT 2.3 <= true;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT 2.3 <= false;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 
 SELECT a1, a1 >= 2.3 FROM t6
@@ -4729,12 +4729,12 @@ SELECT a1, a1 <= 2.3 FROM t6
 SELECT a1, 2.3 >= a1 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a1, 2.3 <= a1 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a2, a2 >= 2.3 FROM t6
  | ---
@@ -4749,12 +4749,12 @@ SELECT a2, a2 <= 2.3 FROM t6
 SELECT a2, 2.3 >= a2 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a2, 2.3 <= a2 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 
 SELECT c, true >= c FROM t8;
@@ -4780,22 +4780,22 @@ SELECT c, false <= c FROM t8;
 SELECT c, c >= true FROM t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT c, c >= false FROM t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT c, c <= true FROM t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT c, c <= false FROM t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 
 SELECT a1, c, a1 >= c FROM t6, t8;
@@ -4811,12 +4811,12 @@ SELECT a1, c, a1 <= c FROM t6, t8;
 SELECT a1, c, c >= a1 FROM t6, t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a1, c, c <= a1 FROM t6, t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a2, c, a2 >= c FROM t6, t8;
  | ---
@@ -4831,12 +4831,12 @@ SELECT a2, c, a2 <= c FROM t6, t8;
 SELECT a2, c, c >= a2 FROM t6, t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a2, c, c <= a2 FROM t6, t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 
 SELECT true == 2.3;
@@ -4862,22 +4862,22 @@ SELECT false != 2.3;
 SELECT 2.3 == true;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT 2.3 == false;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT 2.3 != true;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT 2.3 != false;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 
 SELECT a1, a1 == 2.3 FROM t6
@@ -4893,12 +4893,12 @@ SELECT a1, a1 != 2.3 FROM t6
 SELECT a1, 2.3 == a1 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a1, 2.3 != a1 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a2, a2 == 2.3 FROM t6
  | ---
@@ -4913,12 +4913,12 @@ SELECT a2, a2 != 2.3 FROM t6
 SELECT a2, 2.3 == a2 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a2, 2.3 != a2 FROM t6
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 
 SELECT c, true == c FROM t8;
@@ -4944,22 +4944,22 @@ SELECT c, false != c FROM t8;
 SELECT c, c == true FROM t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT c, c == false FROM t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT c, c != true FROM t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT c, c != false FROM t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 
 SELECT a1, c, a1 == c FROM t6, t8;
@@ -4975,12 +4975,12 @@ SELECT a1, c, a1 != c FROM t6, t8;
 SELECT a1, c, c == a1 FROM t6, t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a1, c, c != a1 FROM t6, t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a2, c, a2 == c FROM t6, t8;
  | ---
@@ -4995,12 +4995,12 @@ SELECT a2, c, a2 != c FROM t6, t8;
 SELECT a2, c, c == a2 FROM t6, t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 SELECT a2, c, c != a2 FROM t6, t8;
  | ---
  | - null
- | - 'Type mismatch: can not convert real to boolean'
+ | - 'Type mismatch: can not convert boolean to real'
  | ...
 
 SELECT true IN (0.1, 1.2, 2.3, 3.4);
@@ -5290,22 +5290,22 @@ SELECT false < 'abc';
 SELECT 'abc' > true;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 SELECT 'abc' > false;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 SELECT 'abc' < true;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 SELECT 'abc' < false;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 
 SELECT d, true > d FROM t9;
@@ -5331,22 +5331,22 @@ SELECT d, false < d FROM t9;
 SELECT d, d > true FROM t9;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 SELECT d, d > false FROM t9;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 SELECT d, d < true FROM t9;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 SELECT d, d < false FROM t9;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 
 SELECT a1, d, a1 > d FROM t6, t9;
@@ -5362,12 +5362,12 @@ SELECT a1, d, a1 < d FROM t6, t9;
 SELECT a1, d, d > a1 FROM t6, t9;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 SELECT a1, d, d < a1 FROM t6, t9;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 SELECT a2, d, a2 > d FROM t6, t9;
  | ---
@@ -5382,12 +5382,12 @@ SELECT a2, d, a2 < d FROM t6, t9;
 SELECT a2, d, d > a2 FROM t6, t9;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 SELECT a2, d, d < a2 FROM t6, t9;
  | ---
  | - null
- | - 'Type mismatch: can not convert text to boolean'
+ | - 'Type mismatch: can not convert boolean to text'
  | ...
 
 SELECT true || 'abc';
diff --git a/test/sql/gh-4230-remove-implicit-cast-for-comparison.result b/test/sql/gh-4230-remove-implicit-cast-for-comparison.result
new file mode 100644
index 0000000..7fdf4e6
--- /dev/null
+++ b/test/sql/gh-4230-remove-implicit-cast-for-comparison.result
@@ -0,0 +1,6519 @@
+-- test-run result file version 2
+-- Make sure that comparison between numeric types works.
+SELECT 2 > 1, 1.5 > 1, 2.5 > 1.5;
+ | ---
+ | - metadata:
+ |   - name: 2 > 1
+ |     type: boolean
+ |   - name: 1.5 > 1
+ |     type: boolean
+ |   - name: 2.5 > 1.5
+ |     type: boolean
+ |   rows:
+ |   - [true, true, true]
+ | ...
+SELECT 2 < 1, 1.5 < 1, 2.5 < 1.5;
+ | ---
+ | - metadata:
+ |   - name: 2 < 1
+ |     type: boolean
+ |   - name: 1.5 < 1
+ |     type: boolean
+ |   - name: 2.5 < 1.5
+ |     type: boolean
+ |   rows:
+ |   - [false, false, false]
+ | ...
+SELECT 2 >= 1, 1.5 >= 1, 2.5 >= 1.5;
+ | ---
+ | - metadata:
+ |   - name: 2 >= 1
+ |     type: any
+ |   - name: 1.5 >= 1
+ |     type: any
+ |   - name: 2.5 >= 1.5
+ |     type: any
+ |   rows:
+ |   - [true, true, true]
+ | ...
+SELECT 2 <= 1, 1.5 <= 1, 2.5 <= 1.5;
+ | ---
+ | - metadata:
+ |   - name: 2 <= 1
+ |     type: boolean
+ |   - name: 1.5 <= 1
+ |     type: boolean
+ |   - name: 2.5 <= 1.5
+ |     type: boolean
+ |   rows:
+ |   - [false, false, false]
+ | ...
+SELECT 2 = 1, 1.5 = 1, 2.5 = 1.5;
+ | ---
+ | - metadata:
+ |   - name: 2 = 1
+ |     type: boolean
+ |   - name: 1.5 = 1
+ |     type: boolean
+ |   - name: 2.5 = 1.5
+ |     type: boolean
+ |   rows:
+ |   - [false, false, false]
+ | ...
+SELECT 2 != 1, 1.5 != 1, 2.5 != 1.5;
+ | ---
+ | - metadata:
+ |   - name: 2 != 1
+ |     type: boolean
+ |   - name: 1.5 != 1
+ |     type: boolean
+ |   - name: 2.5 != 1.5
+ |     type: boolean
+ |   rows:
+ |   - [true, true, true]
+ | ...
+
+CREATE TABLE tn(i INT PRIMARY KEY, a NUMBER, d DOUBLE, u UNSIGNED);
+ | ---
+ | - row_count: 1
+ | ...
+INSERT INTO tn VALUES (1, 2, 3.3, 4);
+ | ---
+ | - row_count: 1
+ | ...
+INSERT INTO tn VALUES (2, 3.5, 3, 4);
+ | ---
+ | - row_count: 1
+ | ...
+SELECT i > 1, i > 1.5, a > 1, a > 1.5, d > 1, d > 1.5, u > 1, u > 1.5 FROM tn;
+ | ---
+ | - metadata:
+ |   - name: i > 1
+ |     type: boolean
+ |   - name: i > 1.5
+ |     type: boolean
+ |   - name: a > 1
+ |     type: boolean
+ |   - name: a > 1.5
+ |     type: boolean
+ |   - name: d > 1
+ |     type: boolean
+ |   - name: d > 1.5
+ |     type: boolean
+ |   - name: u > 1
+ |     type: boolean
+ |   - name: u > 1.5
+ |     type: boolean
+ |   rows:
+ |   - [false, false, true, true, true, true, true, true]
+ |   - [true, true, true, true, true, true, true, true]
+ | ...
+SELECT i < 1, i < 1.5, a < 1, a < 1.5, d < 1, d < 1.5, u < 1, u < 1.5 FROM tn;
+ | ---
+ | - metadata:
+ |   - name: i < 1
+ |     type: boolean
+ |   - name: i < 1.5
+ |     type: boolean
+ |   - name: a < 1
+ |     type: boolean
+ |   - name: a < 1.5
+ |     type: boolean
+ |   - name: d < 1
+ |     type: boolean
+ |   - name: d < 1.5
+ |     type: boolean
+ |   - name: u < 1
+ |     type: boolean
+ |   - name: u < 1.5
+ |     type: boolean
+ |   rows:
+ |   - [false, true, false, false, false, false, false, false]
+ |   - [false, false, false, false, false, false, false, false]
+ | ...
+SELECT i >= 1, i >= 1.5, a >= 1, a >= 1.5, d >= 1, d >= 1.5, u >= 1, u >= 1.5 FROM tn;
+ | ---
+ | - metadata:
+ |   - name: i >= 1
+ |     type: any
+ |   - name: i >= 1.5
+ |     type: any
+ |   - name: a >= 1
+ |     type: any
+ |   - name: a >= 1.5
+ |     type: any
+ |   - name: d >= 1
+ |     type: any
+ |   - name: d >= 1.5
+ |     type: any
+ |   - name: u >= 1
+ |     type: any
+ |   - name: u >= 1.5
+ |     type: any
+ |   rows:
+ |   - [true, false, true, true, true, true, true, true]
+ |   - [true, true, true, true, true, true, true, true]
+ | ...
+SELECT i <= 1, i <= 1.5, a <= 1, a <= 1.5, d <= 1, d <= 1.5, u <= 1, u <= 1.5 FROM tn;
+ | ---
+ | - metadata:
+ |   - name: i <= 1
+ |     type: boolean
+ |   - name: i <= 1.5
+ |     type: boolean
+ |   - name: a <= 1
+ |     type: boolean
+ |   - name: a <= 1.5
+ |     type: boolean
+ |   - name: d <= 1
+ |     type: boolean
+ |   - name: d <= 1.5
+ |     type: boolean
+ |   - name: u <= 1
+ |     type: boolean
+ |   - name: u <= 1.5
+ |     type: boolean
+ |   rows:
+ |   - [true, true, false, false, false, false, false, false]
+ |   - [false, false, false, false, false, false, false, false]
+ | ...
+SELECT i = 1, i = 1.5, a = 1, a = 1.5, d = 1, d = 1.5, u = 1, u = 1.5 FROM tn;
+ | ---
+ | - metadata:
+ |   - name: i = 1
+ |     type: boolean
+ |   - name: i = 1.5
+ |     type: boolean
+ |   - name: a = 1
+ |     type: boolean
+ |   - name: a = 1.5
+ |     type: boolean
+ |   - name: d = 1
+ |     type: boolean
+ |   - name: d = 1.5
+ |     type: boolean
+ |   - name: u = 1
+ |     type: boolean
+ |   - name: u = 1.5
+ |     type: boolean
+ |   rows:
+ |   - [true, false, false, false, false, false, false, false]
+ |   - [false, false, false, false, false, false, false, false]
+ | ...
+SELECT i != 1, i != 1.5, a != 1, a != 1.5, d != 1, d != 1.5, u != 1, u != 1.5 FROM tn;
+ | ---
+ | - metadata:
+ |   - name: i != 1
+ |     type: boolean
+ |   - name: i != 1.5
+ |     type: boolean
+ |   - name: a != 1
+ |     type: boolean
+ |   - name: a != 1.5
+ |     type: boolean
+ |   - name: d != 1
+ |     type: boolean
+ |   - name: d != 1.5
+ |     type: boolean
+ |   - name: u != 1
+ |     type: boolean
+ |   - name: u != 1.5
+ |     type: boolean
+ |   rows:
+ |   - [false, true, true, true, true, true, true, true]
+ |   - [true, true, true, true, true, true, true, true]
+ | ...
+
+SELECT 1 > i, 1.5 > i, 1 > a, 1.5 > a, 1 > d, 1.5 > d, 1 > u, 1.5 > u FROM tn;
+ | ---
+ | - metadata:
+ |   - name: 1 > i
+ |     type: boolean
+ |   - name: 1.5 > i
+ |     type: boolean
+ |   - name: 1 > a
+ |     type: boolean
+ |   - name: 1.5 > a
+ |     type: boolean
+ |   - name: 1 > d
+ |     type: boolean
+ |   - name: 1.5 > d
+ |     type: boolean
+ |   - name: 1 > u
+ |     type: boolean
+ |   - name: 1.5 > u
+ |     type: boolean
+ |   rows:
+ |   - [false, true, false, false, false, false, false, false]
+ |   - [false, false, false, false, false, false, false, false]
+ | ...
+SELECT 1 < i, 1.5 < i, 1 < a, 1.5 < a, 1 < d, 1.5 < d, 1 < u, 1.5 < u FROM tn;
+ | ---
+ | - metadata:
+ |   - name: 1 < i
+ |     type: boolean
+ |   - name: 1.5 < i
+ |     type: boolean
+ |   - name: 1 < a
+ |     type: boolean
+ |   - name: 1.5 < a
+ |     type: boolean
+ |   - name: 1 < d
+ |     type: boolean
+ |   - name: 1.5 < d
+ |     type: boolean
+ |   - name: 1 < u
+ |     type: boolean
+ |   - name: 1.5 < u
+ |     type: boolean
+ |   rows:
+ |   - [false, false, true, true, true, true, true, true]
+ |   - [true, true, true, true, true, true, true, true]
+ | ...
+SELECT 1 >= i, 1.5 >= i, 1 >= a, 1.5 >= a, 1 >= d, 1.5 >= d, 1 >= u, 1.5 >= u FROM tn;
+ | ---
+ | - metadata:
+ |   - name: 1 >= i
+ |     type: any
+ |   - name: 1.5 >= i
+ |     type: any
+ |   - name: 1 >= a
+ |     type: any
+ |   - name: 1.5 >= a
+ |     type: any
+ |   - name: 1 >= d
+ |     type: any
+ |   - name: 1.5 >= d
+ |     type: any
+ |   - name: 1 >= u
+ |     type: any
+ |   - name: 1.5 >= u
+ |     type: any
+ |   rows:
+ |   - [true, true, false, false, false, false, false, false]
+ |   - [false, false, false, false, false, false, false, false]
+ | ...
+SELECT 1 <= i, 1.5 <= i, 1 <= a, 1.5 <= a, 1 <= d, 1.5 <= d, 1 <= u, 1.5 <= u FROM tn;
+ | ---
+ | - metadata:
+ |   - name: 1 <= i
+ |     type: boolean
+ |   - name: 1.5 <= i
+ |     type: boolean
+ |   - name: 1 <= a
+ |     type: boolean
+ |   - name: 1.5 <= a
+ |     type: boolean
+ |   - name: 1 <= d
+ |     type: boolean
+ |   - name: 1.5 <= d
+ |     type: boolean
+ |   - name: 1 <= u
+ |     type: boolean
+ |   - name: 1.5 <= u
+ |     type: boolean
+ |   rows:
+ |   - [true, false, true, true, true, true, true, true]
+ |   - [true, true, true, true, true, true, true, true]
+ | ...
+SELECT 1 = i, 1.5 = i, 1 = a, 1.5 = a, 1 = d, 1.5 = d, 1 = u, 1.5 = u FROM tn;
+ | ---
+ | - metadata:
+ |   - name: 1 = i
+ |     type: boolean
+ |   - name: 1.5 = i
+ |     type: boolean
+ |   - name: 1 = a
+ |     type: boolean
+ |   - name: 1.5 = a
+ |     type: boolean
+ |   - name: 1 = d
+ |     type: boolean
+ |   - name: 1.5 = d
+ |     type: boolean
+ |   - name: 1 = u
+ |     type: boolean
+ |   - name: 1.5 = u
+ |     type: boolean
+ |   rows:
+ |   - [true, false, false, false, false, false, false, false]
+ |   - [false, false, false, false, false, false, false, false]
+ | ...
+SELECT 1 != i, 1.5 != i, 1 != a, 1.5 != a, 1 != d, 1.5 != d, 1 != u, 1.5 != u FROM tn;
+ | ---
+ | - metadata:
+ |   - name: 1 != i
+ |     type: boolean
+ |   - name: 1.5 != i
+ |     type: boolean
+ |   - name: 1 != a
+ |     type: boolean
+ |   - name: 1.5 != a
+ |     type: boolean
+ |   - name: 1 != d
+ |     type: boolean
+ |   - name: 1.5 != d
+ |     type: boolean
+ |   - name: 1 != u
+ |     type: boolean
+ |   - name: 1.5 != u
+ |     type: boolean
+ |   rows:
+ |   - [false, true, true, true, true, true, true, true]
+ |   - [true, true, true, true, true, true, true, true]
+ | ...
+
+SELECT i > i, i > a, i > d, i > u, a > a, a > d, a > u, d > d, d > u, u > u FROM tn;
+ | ---
+ | - metadata:
+ |   - name: i > i
+ |     type: boolean
+ |   - name: i > a
+ |     type: boolean
+ |   - name: i > d
+ |     type: boolean
+ |   - name: i > u
+ |     type: boolean
+ |   - name: a > a
+ |     type: boolean
+ |   - name: a > d
+ |     type: boolean
+ |   - name: a > u
+ |     type: boolean
+ |   - name: d > d
+ |     type: boolean
+ |   - name: d > u
+ |     type: boolean
+ |   - name: u > u
+ |     type: boolean
+ |   rows:
+ |   - [false, false, false, false, false, false, false, false, false, false]
+ |   - [false, false, false, false, false, true, false, false, false, false]
+ | ...
+SELECT i < i, i < a, i < d, i < u, a < a, a < d, a < u, d < d, d < u, u < u FROM tn;
+ | ---
+ | - metadata:
+ |   - name: i < i
+ |     type: boolean
+ |   - name: i < a
+ |     type: boolean
+ |   - name: i < d
+ |     type: boolean
+ |   - name: i < u
+ |     type: boolean
+ |   - name: a < a
+ |     type: boolean
+ |   - name: a < d
+ |     type: boolean
+ |   - name: a < u
+ |     type: boolean
+ |   - name: d < d
+ |     type: boolean
+ |   - name: d < u
+ |     type: boolean
+ |   - name: u < u
+ |     type: boolean
+ |   rows:
+ |   - [false, true, true, true, false, true, true, false, true, false]
+ |   - [false, true, true, true, false, false, true, false, true, false]
+ | ...
+SELECT i >= i, i >= a, i >= d, i >= u, a >= a, a >= d, a >= u, d >= d, d >= u, u >= u FROM tn;
+ | ---
+ | - metadata:
+ |   - name: i >= i
+ |     type: any
+ |   - name: i >= a
+ |     type: any
+ |   - name: i >= d
+ |     type: any
+ |   - name: i >= u
+ |     type: any
+ |   - name: a >= a
+ |     type: any
+ |   - name: a >= d
+ |     type: any
+ |   - name: a >= u
+ |     type: any
+ |   - name: d >= d
+ |     type: any
+ |   - name: d >= u
+ |     type: any
+ |   - name: u >= u
+ |     type: any
+ |   rows:
+ |   - [true, false, false, false, true, false, false, true, false, true]
+ |   - [true, false, false, false, true, true, false, true, false, true]
+ | ...
+SELECT i <= i, i <= a, i <= d, i <= u, a <= a, a <= d, a <= u, d <= d, d <= u, u <= u FROM tn;
+ | ---
+ | - metadata:
+ |   - name: i <= i
+ |     type: boolean
+ |   - name: i <= a
+ |     type: boolean
+ |   - name: i <= d
+ |     type: boolean
+ |   - name: i <= u
+ |     type: boolean
+ |   - name: a <= a
+ |     type: boolean
+ |   - name: a <= d
+ |     type: boolean
+ |   - name: a <= u
+ |     type: boolean
+ |   - name: d <= d
+ |     type: boolean
+ |   - name: d <= u
+ |     type: boolean
+ |   - name: u <= u
+ |     type: boolean
+ |   rows:
+ |   - [true, true, true, true, true, true, true, true, true, true]
+ |   - [true, true, true, true, true, false, true, true, true, true]
+ | ...
+SELECT i = i, i = a, i = d, i = u, a = a, a = d, a = u, d = d, d = u, u = u FROM tn;
+ | ---
+ | - metadata:
+ |   - name: i = i
+ |     type: boolean
+ |   - name: i = a
+ |     type: boolean
+ |   - name: i = d
+ |     type: boolean
+ |   - name: i = u
+ |     type: boolean
+ |   - name: a = a
+ |     type: boolean
+ |   - name: a = d
+ |     type: boolean
+ |   - name: a = u
+ |     type: boolean
+ |   - name: d = d
+ |     type: boolean
+ |   - name: d = u
+ |     type: boolean
+ |   - name: u = u
+ |     type: boolean
+ |   rows:
+ |   - [true, false, false, false, true, false, false, true, false, true]
+ |   - [true, false, false, false, true, false, false, true, false, true]
+ | ...
+SELECT i != i, i != a, i != d, i != u, a != a, a != d, a != u, d != d, d != u, u != u FROM tn;
+ | ---
+ | - metadata:
+ |   - name: i != i
+ |     type: boolean
+ |   - name: i != a
+ |     type: boolean
+ |   - name: i != d
+ |     type: boolean
+ |   - name: i != u
+ |     type: boolean
+ |   - name: a != a
+ |     type: boolean
+ |   - name: a != d
+ |     type: boolean
+ |   - name: a != u
+ |     type: boolean
+ |   - name: d != d
+ |     type: boolean
+ |   - name: d != u
+ |     type: boolean
+ |   - name: u != u
+ |     type: boolean
+ |   rows:
+ |   - [false, true, true, true, false, true, true, false, true, false]
+ |   - [false, true, true, true, false, true, true, false, true, false]
+ | ...
+
+-- Make sure that comparison between BOOLEAN values works.
+SELECT true > false;
+ | ---
+ | - metadata:
+ |   - name: true > false
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+SELECT true < false;
+ | ---
+ | - metadata:
+ |   - name: true < false
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT true >= false;
+ | ---
+ | - metadata:
+ |   - name: true >= false
+ |     type: any
+ |   rows:
+ |   - [true]
+ | ...
+SELECT true <= false;
+ | ---
+ | - metadata:
+ |   - name: true <= false
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT true = false;
+ | ---
+ | - metadata:
+ |   - name: true = false
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT true != false;
+ | ---
+ | - metadata:
+ |   - name: true != false
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+
+CREATE TABLE tb(b1 BOOLEAN PRIMARY KEY, b2 BOOLEAN);
+ | ---
+ | - row_count: 1
+ | ...
+INSERT INTO tb VALUES (true, false);
+ | ---
+ | - row_count: 1
+ | ...
+SELECT b1 > true FROM tb;
+ | ---
+ | - metadata:
+ |   - name: b1 > true
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT b1 < true FROM tb;
+ | ---
+ | - metadata:
+ |   - name: b1 < true
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT b1 >= true FROM tb;
+ | ---
+ | - metadata:
+ |   - name: b1 >= true
+ |     type: any
+ |   rows:
+ |   - [true]
+ | ...
+SELECT b1 <= true FROM tb;
+ | ---
+ | - metadata:
+ |   - name: b1 <= true
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+SELECT b1 = true FROM tb;
+ | ---
+ | - metadata:
+ |   - name: b1 = true
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+SELECT b1 != true FROM tb;
+ | ---
+ | - metadata:
+ |   - name: b1 != true
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+
+SELECT true > b1 FROM tb;
+ | ---
+ | - metadata:
+ |   - name: true > b1
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT true < b1 FROM tb;
+ | ---
+ | - metadata:
+ |   - name: true < b1
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT true >= b1 FROM tb;
+ | ---
+ | - metadata:
+ |   - name: true >= b1
+ |     type: any
+ |   rows:
+ |   - [true]
+ | ...
+SELECT true <= b1 FROM tb;
+ | ---
+ | - metadata:
+ |   - name: true <= b1
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+SELECT true = b1 FROM tb;
+ | ---
+ | - metadata:
+ |   - name: true = b1
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+SELECT true != b1 FROM tb;
+ | ---
+ | - metadata:
+ |   - name: true != b1
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+
+SELECT b1 > b2 FROM tb;
+ | ---
+ | - metadata:
+ |   - name: b1 > b2
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+SELECT b1 < b2 FROM tb;
+ | ---
+ | - metadata:
+ |   - name: b1 < b2
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT b1 >= b2 FROM tb;
+ | ---
+ | - metadata:
+ |   - name: b1 >= b2
+ |     type: any
+ |   rows:
+ |   - [true]
+ | ...
+SELECT b1 <= b2 FROM tb;
+ | ---
+ | - metadata:
+ |   - name: b1 <= b2
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT b1 = b2 FROM tb;
+ | ---
+ | - metadata:
+ |   - name: b1 = b2
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT b1 != b2 FROM tb;
+ | ---
+ | - metadata:
+ |   - name: b1 != b2
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+
+-- Make sure that comparison between STRING values works.
+SELECT '123' > '456';
+ | ---
+ | - metadata:
+ |   - name: '''123'' > ''456'''
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT '123' < '456';
+ | ---
+ | - metadata:
+ |   - name: '''123'' < ''456'''
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+SELECT '123' >= '456';
+ | ---
+ | - metadata:
+ |   - name: '''123'' >= ''456'''
+ |     type: any
+ |   rows:
+ |   - [false]
+ | ...
+SELECT '123' <= '456';
+ | ---
+ | - metadata:
+ |   - name: '''123'' <= ''456'''
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+SELECT '123' = '456';
+ | ---
+ | - metadata:
+ |   - name: '''123'' = ''456'''
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT '123' != '456';
+ | ---
+ | - metadata:
+ |   - name: '''123'' != ''456'''
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+
+CREATE TABLE ts(s1 STRING PRIMARY KEY, s2 STRING);
+ | ---
+ | - row_count: 1
+ | ...
+INSERT INTO ts VALUES ('12', '32');
+ | ---
+ | - row_count: 1
+ | ...
+SELECT s1 > '123' FROM ts;
+ | ---
+ | - metadata:
+ |   - name: s1 > '123'
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT s1 < '123' FROM ts;
+ | ---
+ | - metadata:
+ |   - name: s1 < '123'
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+SELECT s1 >= '123' FROM ts;
+ | ---
+ | - metadata:
+ |   - name: s1 >= '123'
+ |     type: any
+ |   rows:
+ |   - [false]
+ | ...
+SELECT s1 <= '123' FROM ts;
+ | ---
+ | - metadata:
+ |   - name: s1 <= '123'
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+SELECT s1 = '123' FROM ts;
+ | ---
+ | - metadata:
+ |   - name: s1 = '123'
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT s1 != '123' FROM ts;
+ | ---
+ | - metadata:
+ |   - name: s1 != '123'
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+
+SELECT '123' > s1 FROM ts;
+ | ---
+ | - metadata:
+ |   - name: '''123'' > s1'
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+SELECT '123' < s1 FROM ts;
+ | ---
+ | - metadata:
+ |   - name: '''123'' < s1'
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT '123' >= s1 FROM ts;
+ | ---
+ | - metadata:
+ |   - name: '''123'' >= s1'
+ |     type: any
+ |   rows:
+ |   - [true]
+ | ...
+SELECT '123' <= s1 FROM ts;
+ | ---
+ | - metadata:
+ |   - name: '''123'' <= s1'
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT '123' = s1 FROM ts;
+ | ---
+ | - metadata:
+ |   - name: '''123'' = s1'
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT '123' != s1 FROM ts;
+ | ---
+ | - metadata:
+ |   - name: '''123'' != s1'
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+
+SELECT s1 > s2 FROM ts;
+ | ---
+ | - metadata:
+ |   - name: s1 > s2
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT s1 < s2 FROM ts;
+ | ---
+ | - metadata:
+ |   - name: s1 < s2
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+SELECT s1 >= s2 FROM ts;
+ | ---
+ | - metadata:
+ |   - name: s1 >= s2
+ |     type: any
+ |   rows:
+ |   - [false]
+ | ...
+SELECT s1 <= s2 FROM ts;
+ | ---
+ | - metadata:
+ |   - name: s1 <= s2
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+SELECT s1 = s2 FROM ts;
+ | ---
+ | - metadata:
+ |   - name: s1 = s2
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT s1 != s2 FROM ts;
+ | ---
+ | - metadata:
+ |   - name: s1 != s2
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+
+-- Make sure that comparison between VARBINARY values works.
+SELECT X'3139' > X'3537';
+ | ---
+ | - metadata:
+ |   - name: X'3139' > X'3537'
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT X'3139' < X'3537';
+ | ---
+ | - metadata:
+ |   - name: X'3139' < X'3537'
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+SELECT X'3139' >= X'3537';
+ | ---
+ | - metadata:
+ |   - name: X'3139' >= X'3537'
+ |     type: any
+ |   rows:
+ |   - [false]
+ | ...
+SELECT X'3139' <= X'3537';
+ | ---
+ | - metadata:
+ |   - name: X'3139' <= X'3537'
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+SELECT X'3139' = X'3537';
+ | ---
+ | - metadata:
+ |   - name: X'3139' = X'3537'
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT X'3139' != X'3537';
+ | ---
+ | - metadata:
+ |   - name: X'3139' != X'3537'
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+
+CREATE TABLE tv(v1 VARBINARY PRIMARY KEY, v2 VARBINARY);
+ | ---
+ | - row_count: 1
+ | ...
+INSERT INTO tv VALUES (X'3333', X'3432');
+ | ---
+ | - row_count: 1
+ | ...
+SELECT v1 > X'3139' FROM tv;
+ | ---
+ | - metadata:
+ |   - name: v1 > X'3139'
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+SELECT v1 < X'3139' FROM tv;
+ | ---
+ | - metadata:
+ |   - name: v1 < X'3139'
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT v1 >= X'3139' FROM tv;
+ | ---
+ | - metadata:
+ |   - name: v1 >= X'3139'
+ |     type: any
+ |   rows:
+ |   - [true]
+ | ...
+SELECT v1 <= X'3139' FROM tv;
+ | ---
+ | - metadata:
+ |   - name: v1 <= X'3139'
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT v1 = X'3139' FROM tv;
+ | ---
+ | - metadata:
+ |   - name: v1 = X'3139'
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT v1 != X'3139' FROM tv;
+ | ---
+ | - metadata:
+ |   - name: v1 != X'3139'
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+
+SELECT X'3139' > v1 FROM tv;
+ | ---
+ | - metadata:
+ |   - name: X'3139' > v1
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT X'3139' < v1 FROM tv;
+ | ---
+ | - metadata:
+ |   - name: X'3139' < v1
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+SELECT X'3139' >= v1 FROM tv;
+ | ---
+ | - metadata:
+ |   - name: X'3139' >= v1
+ |     type: any
+ |   rows:
+ |   - [false]
+ | ...
+SELECT X'3139' <= v1 FROM tv;
+ | ---
+ | - metadata:
+ |   - name: X'3139' <= v1
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+SELECT X'3139' = v1 FROM tv;
+ | ---
+ | - metadata:
+ |   - name: X'3139' = v1
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT X'3139' != v1 FROM tv;
+ | ---
+ | - metadata:
+ |   - name: X'3139' != v1
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+
+SELECT v1 > v2 FROM tv;
+ | ---
+ | - metadata:
+ |   - name: v1 > v2
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT v1 < v2 FROM tv;
+ | ---
+ | - metadata:
+ |   - name: v1 < v2
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+SELECT v1 >= v2 FROM tv;
+ | ---
+ | - metadata:
+ |   - name: v1 >= v2
+ |     type: any
+ |   rows:
+ |   - [false]
+ | ...
+SELECT v1 <= v2 FROM tv;
+ | ---
+ | - metadata:
+ |   - name: v1 <= v2
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+SELECT v1 = v2 FROM tv;
+ | ---
+ | - metadata:
+ |   - name: v1 = v2
+ |     type: boolean
+ |   rows:
+ |   - [false]
+ | ...
+SELECT v1 != v2 FROM tv;
+ | ---
+ | - metadata:
+ |   - name: v1 != v2
+ |     type: boolean
+ |   rows:
+ |   - [true]
+ | ...
+
+-- Make sure, that comparison with NULL returns NULL.
+SELECT NULL > NULL, NULL > 1, NULL > 1.5, NULL > true, NULL > '123', NULL > X'3139';
+ | ---
+ | - metadata:
+ |   - name: NULL > NULL
+ |     type: boolean
+ |   - name: NULL > 1
+ |     type: boolean
+ |   - name: NULL > 1.5
+ |     type: boolean
+ |   - name: NULL > true
+ |     type: boolean
+ |   - name: NULL > '123'
+ |     type: boolean
+ |   - name: NULL > X'3139'
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null]
+ | ...
+SELECT NULL < NULL, NULL < 1, NULL < 1.5, NULL < true, NULL < '123', NULL < X'3139';
+ | ---
+ | - metadata:
+ |   - name: NULL < NULL
+ |     type: boolean
+ |   - name: NULL < 1
+ |     type: boolean
+ |   - name: NULL < 1.5
+ |     type: boolean
+ |   - name: NULL < true
+ |     type: boolean
+ |   - name: NULL < '123'
+ |     type: boolean
+ |   - name: NULL < X'3139'
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null]
+ | ...
+SELECT NULL >= NULL, NULL >= 1, NULL >= 1.5, NULL >= true, NULL >= '123', NULL >= X'3139';
+ | ---
+ | - metadata:
+ |   - name: NULL >= NULL
+ |     type: any
+ |   - name: NULL >= 1
+ |     type: any
+ |   - name: NULL >= 1.5
+ |     type: any
+ |   - name: NULL >= true
+ |     type: any
+ |   - name: NULL >= '123'
+ |     type: any
+ |   - name: NULL >= X'3139'
+ |     type: any
+ |   rows:
+ |   - [null, null, null, null, null, null]
+ | ...
+SELECT NULL <= NULL, NULL <= 1, NULL <= 1.5, NULL <= true, NULL <= '123', NULL <= X'3139';
+ | ---
+ | - metadata:
+ |   - name: NULL <= NULL
+ |     type: boolean
+ |   - name: NULL <= 1
+ |     type: boolean
+ |   - name: NULL <= 1.5
+ |     type: boolean
+ |   - name: NULL <= true
+ |     type: boolean
+ |   - name: NULL <= '123'
+ |     type: boolean
+ |   - name: NULL <= X'3139'
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null]
+ | ...
+SELECT NULL = NULL, NULL = 1, NULL = 1.5, NULL = true, NULL = '123', NULL = X'3139';
+ | ---
+ | - metadata:
+ |   - name: NULL = NULL
+ |     type: boolean
+ |   - name: NULL = 1
+ |     type: boolean
+ |   - name: NULL = 1.5
+ |     type: boolean
+ |   - name: NULL = true
+ |     type: boolean
+ |   - name: NULL = '123'
+ |     type: boolean
+ |   - name: NULL = X'3139'
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null]
+ | ...
+SELECT NULL != NULL, NULL != 1, NULL != 1.5, NULL != true, NULL != '123', NULL != X'3139';
+ | ---
+ | - metadata:
+ |   - name: NULL != NULL
+ |     type: boolean
+ |   - name: NULL != 1
+ |     type: boolean
+ |   - name: NULL != 1.5
+ |     type: boolean
+ |   - name: NULL != true
+ |     type: boolean
+ |   - name: NULL != '123'
+ |     type: boolean
+ |   - name: NULL != X'3139'
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null]
+ | ...
+
+SELECT 1 > NULL, 1.5 > NULL, true > NULL, '123' > NULL, X'3139' > NULL;
+ | ---
+ | - metadata:
+ |   - name: 1 > NULL
+ |     type: boolean
+ |   - name: 1.5 > NULL
+ |     type: boolean
+ |   - name: true > NULL
+ |     type: boolean
+ |   - name: '''123'' > NULL'
+ |     type: boolean
+ |   - name: X'3139' > NULL
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null]
+ | ...
+SELECT 1 < NULL, 1.5 < NULL, true < NULL, '123' < NULL, X'3139' < NULL;
+ | ---
+ | - metadata:
+ |   - name: 1 < NULL
+ |     type: boolean
+ |   - name: 1.5 < NULL
+ |     type: boolean
+ |   - name: true < NULL
+ |     type: boolean
+ |   - name: '''123'' < NULL'
+ |     type: boolean
+ |   - name: X'3139' < NULL
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null]
+ | ...
+SELECT 1 >= NULL, 1.5 >= NULL, true >= NULL, '123' >= NULL, X'3139' >= NULL;
+ | ---
+ | - metadata:
+ |   - name: 1 >= NULL
+ |     type: any
+ |   - name: 1.5 >= NULL
+ |     type: any
+ |   - name: true >= NULL
+ |     type: any
+ |   - name: '''123'' >= NULL'
+ |     type: any
+ |   - name: X'3139' >= NULL
+ |     type: any
+ |   rows:
+ |   - [null, null, null, null, null]
+ | ...
+SELECT 1 <= NULL, 1.5 <= NULL, true <= NULL, '123' <= NULL, X'3139' <= NULL;
+ | ---
+ | - metadata:
+ |   - name: 1 <= NULL
+ |     type: boolean
+ |   - name: 1.5 <= NULL
+ |     type: boolean
+ |   - name: true <= NULL
+ |     type: boolean
+ |   - name: '''123'' <= NULL'
+ |     type: boolean
+ |   - name: X'3139' <= NULL
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null]
+ | ...
+SELECT 1 = NULL, 1.5 = NULL, true = NULL, '123' = NULL, X'3139' = NULL;
+ | ---
+ | - metadata:
+ |   - name: 1 = NULL
+ |     type: boolean
+ |   - name: 1.5 = NULL
+ |     type: boolean
+ |   - name: true = NULL
+ |     type: boolean
+ |   - name: '''123'' = NULL'
+ |     type: boolean
+ |   - name: X'3139' = NULL
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null]
+ | ...
+SELECT 1 != NULL, 1.5 != NULL, true != NULL, '123' != NULL, X'3139' != NULL;
+ | ---
+ | - metadata:
+ |   - name: 1 != NULL
+ |     type: boolean
+ |   - name: 1.5 != NULL
+ |     type: boolean
+ |   - name: true != NULL
+ |     type: boolean
+ |   - name: '''123'' != NULL'
+ |     type: boolean
+ |   - name: X'3139' != NULL
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null]
+ | ...
+
+SELECT NULL > i, NULL > a, NULL > d, NULL > u, NULL > b1, NULL > s1, NULL > v1 FROM tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: NULL > i
+ |     type: boolean
+ |   - name: NULL > a
+ |     type: boolean
+ |   - name: NULL > d
+ |     type: boolean
+ |   - name: NULL > u
+ |     type: boolean
+ |   - name: NULL > b1
+ |     type: boolean
+ |   - name: NULL > s1
+ |     type: boolean
+ |   - name: NULL > v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT NULL < i, NULL < a, NULL < d, NULL < u, NULL < b1, NULL < s1, NULL < v1 FROM tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: NULL < i
+ |     type: boolean
+ |   - name: NULL < a
+ |     type: boolean
+ |   - name: NULL < d
+ |     type: boolean
+ |   - name: NULL < u
+ |     type: boolean
+ |   - name: NULL < b1
+ |     type: boolean
+ |   - name: NULL < s1
+ |     type: boolean
+ |   - name: NULL < v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT NULL >= i, NULL >= a, NULL >= d, NULL >= u, NULL >= b1, NULL >= s1, NULL >= v1 FROM tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: NULL >= i
+ |     type: any
+ |   - name: NULL >= a
+ |     type: any
+ |   - name: NULL >= d
+ |     type: any
+ |   - name: NULL >= u
+ |     type: any
+ |   - name: NULL >= b1
+ |     type: any
+ |   - name: NULL >= s1
+ |     type: any
+ |   - name: NULL >= v1
+ |     type: any
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT NULL <= i, NULL <= a, NULL <= d, NULL <= u, NULL <= b1, NULL <= s1, NULL <= v1 FROM tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: NULL <= i
+ |     type: boolean
+ |   - name: NULL <= a
+ |     type: boolean
+ |   - name: NULL <= d
+ |     type: boolean
+ |   - name: NULL <= u
+ |     type: boolean
+ |   - name: NULL <= b1
+ |     type: boolean
+ |   - name: NULL <= s1
+ |     type: boolean
+ |   - name: NULL <= v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT NULL = i, NULL = a, NULL = d, NULL = u, NULL = b1, NULL = s1, NULL = v1 FROM tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: NULL = i
+ |     type: boolean
+ |   - name: NULL = a
+ |     type: boolean
+ |   - name: NULL = d
+ |     type: boolean
+ |   - name: NULL = u
+ |     type: boolean
+ |   - name: NULL = b1
+ |     type: boolean
+ |   - name: NULL = s1
+ |     type: boolean
+ |   - name: NULL = v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT NULL != i, NULL != a, NULL != d, NULL != u, NULL != b1, NULL != s1, NULL != v1 FROM tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: NULL != i
+ |     type: boolean
+ |   - name: NULL != a
+ |     type: boolean
+ |   - name: NULL != d
+ |     type: boolean
+ |   - name: NULL != u
+ |     type: boolean
+ |   - name: NULL != b1
+ |     type: boolean
+ |   - name: NULL != s1
+ |     type: boolean
+ |   - name: NULL != v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+
+CREATE TABLE t0(pk INT PRIMARY KEY, i0 INT, a0 NUMBER, d0 DOUBLE, u0 UNSIGNED, b0 BOOLEAN, s0 STRING, v0 VARBINARY, sc0 SCALAR);
+ | ---
+ | - row_count: 1
+ | ...
+INSERT INTO t0 VALUES (1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+ | ---
+ | - row_count: 1
+ | ...
+SELECT i0 > i, i0 > a, i0 > d, i0 > u, i0 > b1, i0 > s1, i0 > v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i0 > i
+ |     type: boolean
+ |   - name: i0 > a
+ |     type: boolean
+ |   - name: i0 > d
+ |     type: boolean
+ |   - name: i0 > u
+ |     type: boolean
+ |   - name: i0 > b1
+ |     type: boolean
+ |   - name: i0 > s1
+ |     type: boolean
+ |   - name: i0 > v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i0 < i, i0 < a, i0 < d, i0 < u, i0 < b1, i0 < s1, i0 < v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i0 < i
+ |     type: boolean
+ |   - name: i0 < a
+ |     type: boolean
+ |   - name: i0 < d
+ |     type: boolean
+ |   - name: i0 < u
+ |     type: boolean
+ |   - name: i0 < b1
+ |     type: boolean
+ |   - name: i0 < s1
+ |     type: boolean
+ |   - name: i0 < v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i0 >= i, i0 >= a, i0 >= d, i0 >= u, i0 >= b1, i0 >= s1, i0 >= v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i0 >= i
+ |     type: any
+ |   - name: i0 >= a
+ |     type: any
+ |   - name: i0 >= d
+ |     type: any
+ |   - name: i0 >= u
+ |     type: any
+ |   - name: i0 >= b1
+ |     type: any
+ |   - name: i0 >= s1
+ |     type: any
+ |   - name: i0 >= v1
+ |     type: any
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i0 <= i, i0 <= a, i0 <= d, i0 <= u, i0 <= b1, i0 <= s1, i0 <= v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i0 <= i
+ |     type: boolean
+ |   - name: i0 <= a
+ |     type: boolean
+ |   - name: i0 <= d
+ |     type: boolean
+ |   - name: i0 <= u
+ |     type: boolean
+ |   - name: i0 <= b1
+ |     type: boolean
+ |   - name: i0 <= s1
+ |     type: boolean
+ |   - name: i0 <= v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i0 = i, i0 = a, i0 = d, i0 = u, i0 = b1, i0 = s1, i0 = v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i0 = i
+ |     type: boolean
+ |   - name: i0 = a
+ |     type: boolean
+ |   - name: i0 = d
+ |     type: boolean
+ |   - name: i0 = u
+ |     type: boolean
+ |   - name: i0 = b1
+ |     type: boolean
+ |   - name: i0 = s1
+ |     type: boolean
+ |   - name: i0 = v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i0 != i, i0 != a, i0 != d, i0 != u, i0 != b1, i0 != s1, i0 != v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i0 != i
+ |     type: boolean
+ |   - name: i0 != a
+ |     type: boolean
+ |   - name: i0 != d
+ |     type: boolean
+ |   - name: i0 != u
+ |     type: boolean
+ |   - name: i0 != b1
+ |     type: boolean
+ |   - name: i0 != s1
+ |     type: boolean
+ |   - name: i0 != v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+
+SELECT i > i0, a > i0, d > i0, u > i0, b1 > i0, s1 > i0, v1 > i0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i > i0
+ |     type: boolean
+ |   - name: a > i0
+ |     type: boolean
+ |   - name: d > i0
+ |     type: boolean
+ |   - name: u > i0
+ |     type: boolean
+ |   - name: b1 > i0
+ |     type: boolean
+ |   - name: s1 > i0
+ |     type: boolean
+ |   - name: v1 > i0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i < i0, a < i0, d < i0, u < i0, b1 < i0, s1 < i0, v1 < i0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i < i0
+ |     type: boolean
+ |   - name: a < i0
+ |     type: boolean
+ |   - name: d < i0
+ |     type: boolean
+ |   - name: u < i0
+ |     type: boolean
+ |   - name: b1 < i0
+ |     type: boolean
+ |   - name: s1 < i0
+ |     type: boolean
+ |   - name: v1 < i0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i >= i0, a >= i0, d >= i0, u >= i0, b1 >= i0, s1 >= i0, v1 >= i0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i >= i0
+ |     type: any
+ |   - name: a >= i0
+ |     type: any
+ |   - name: d >= i0
+ |     type: any
+ |   - name: u >= i0
+ |     type: any
+ |   - name: b1 >= i0
+ |     type: any
+ |   - name: s1 >= i0
+ |     type: any
+ |   - name: v1 >= i0
+ |     type: any
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i <= i0, a <= i0, d <= i0, u <= i0, b1 <= i0, s1 <= i0, v1 <= i0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i <= i0
+ |     type: boolean
+ |   - name: a <= i0
+ |     type: boolean
+ |   - name: d <= i0
+ |     type: boolean
+ |   - name: u <= i0
+ |     type: boolean
+ |   - name: b1 <= i0
+ |     type: boolean
+ |   - name: s1 <= i0
+ |     type: boolean
+ |   - name: v1 <= i0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i = i0, a = i0, d = i0, u = i0, b1 = i0, s1 = i0, v1 = i0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i = i0
+ |     type: boolean
+ |   - name: a = i0
+ |     type: boolean
+ |   - name: d = i0
+ |     type: boolean
+ |   - name: u = i0
+ |     type: boolean
+ |   - name: b1 = i0
+ |     type: boolean
+ |   - name: s1 = i0
+ |     type: boolean
+ |   - name: v1 = i0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i != i0, a != i0, d != i0, u != i0, b1 != i0, s1 != i0, v1 != i0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i != i0
+ |     type: boolean
+ |   - name: a != i0
+ |     type: boolean
+ |   - name: d != i0
+ |     type: boolean
+ |   - name: u != i0
+ |     type: boolean
+ |   - name: b1 != i0
+ |     type: boolean
+ |   - name: s1 != i0
+ |     type: boolean
+ |   - name: v1 != i0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+
+SELECT a0 > i, a0 > a, a0 > d, a0 > u, a0 > b1, a0 > s1, a0 > v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: a0 > i
+ |     type: boolean
+ |   - name: a0 > a
+ |     type: boolean
+ |   - name: a0 > d
+ |     type: boolean
+ |   - name: a0 > u
+ |     type: boolean
+ |   - name: a0 > b1
+ |     type: boolean
+ |   - name: a0 > s1
+ |     type: boolean
+ |   - name: a0 > v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT a0 < i, a0 < a, a0 < d, a0 < u, a0 < b1, a0 < s1, a0 < v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: a0 < i
+ |     type: boolean
+ |   - name: a0 < a
+ |     type: boolean
+ |   - name: a0 < d
+ |     type: boolean
+ |   - name: a0 < u
+ |     type: boolean
+ |   - name: a0 < b1
+ |     type: boolean
+ |   - name: a0 < s1
+ |     type: boolean
+ |   - name: a0 < v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT a0 >= i, a0 >= a, a0 >= d, a0 >= u, a0 >= b1, a0 >= s1, a0 >= v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: a0 >= i
+ |     type: any
+ |   - name: a0 >= a
+ |     type: any
+ |   - name: a0 >= d
+ |     type: any
+ |   - name: a0 >= u
+ |     type: any
+ |   - name: a0 >= b1
+ |     type: any
+ |   - name: a0 >= s1
+ |     type: any
+ |   - name: a0 >= v1
+ |     type: any
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT a0 <= i, a0 <= a, a0 <= d, a0 <= u, a0 <= b1, a0 <= s1, a0 <= v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: a0 <= i
+ |     type: boolean
+ |   - name: a0 <= a
+ |     type: boolean
+ |   - name: a0 <= d
+ |     type: boolean
+ |   - name: a0 <= u
+ |     type: boolean
+ |   - name: a0 <= b1
+ |     type: boolean
+ |   - name: a0 <= s1
+ |     type: boolean
+ |   - name: a0 <= v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT a0 = i, a0 = a, a0 = d, a0 = u, a0 = b1, a0 = s1, a0 = v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: a0 = i
+ |     type: boolean
+ |   - name: a0 = a
+ |     type: boolean
+ |   - name: a0 = d
+ |     type: boolean
+ |   - name: a0 = u
+ |     type: boolean
+ |   - name: a0 = b1
+ |     type: boolean
+ |   - name: a0 = s1
+ |     type: boolean
+ |   - name: a0 = v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT a0 != i, a0 != a, a0 != d, a0 != u, a0 != b1, a0 != s1, a0 != v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: a0 != i
+ |     type: boolean
+ |   - name: a0 != a
+ |     type: boolean
+ |   - name: a0 != d
+ |     type: boolean
+ |   - name: a0 != u
+ |     type: boolean
+ |   - name: a0 != b1
+ |     type: boolean
+ |   - name: a0 != s1
+ |     type: boolean
+ |   - name: a0 != v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+
+SELECT i > a0, a > a0, d > a0, u > a0, b1 > a0, s1 > a0, v1 > a0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i > a0
+ |     type: boolean
+ |   - name: a > a0
+ |     type: boolean
+ |   - name: d > a0
+ |     type: boolean
+ |   - name: u > a0
+ |     type: boolean
+ |   - name: b1 > a0
+ |     type: boolean
+ |   - name: s1 > a0
+ |     type: boolean
+ |   - name: v1 > a0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i < a0, a < a0, d < a0, u < a0, b1 < a0, s1 < a0, v1 < a0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i < a0
+ |     type: boolean
+ |   - name: a < a0
+ |     type: boolean
+ |   - name: d < a0
+ |     type: boolean
+ |   - name: u < a0
+ |     type: boolean
+ |   - name: b1 < a0
+ |     type: boolean
+ |   - name: s1 < a0
+ |     type: boolean
+ |   - name: v1 < a0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i >= a0, a >= a0, d >= a0, u >= a0, b1 >= a0, s1 >= a0, v1 >= a0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i >= a0
+ |     type: any
+ |   - name: a >= a0
+ |     type: any
+ |   - name: d >= a0
+ |     type: any
+ |   - name: u >= a0
+ |     type: any
+ |   - name: b1 >= a0
+ |     type: any
+ |   - name: s1 >= a0
+ |     type: any
+ |   - name: v1 >= a0
+ |     type: any
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i <= a0, a <= a0, d <= a0, u <= a0, b1 <= a0, s1 <= a0, v1 <= a0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i <= a0
+ |     type: boolean
+ |   - name: a <= a0
+ |     type: boolean
+ |   - name: d <= a0
+ |     type: boolean
+ |   - name: u <= a0
+ |     type: boolean
+ |   - name: b1 <= a0
+ |     type: boolean
+ |   - name: s1 <= a0
+ |     type: boolean
+ |   - name: v1 <= a0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i = a0, a = a0, d = a0, u = a0, b1 = a0, s1 = a0, v1 = a0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i = a0
+ |     type: boolean
+ |   - name: a = a0
+ |     type: boolean
+ |   - name: d = a0
+ |     type: boolean
+ |   - name: u = a0
+ |     type: boolean
+ |   - name: b1 = a0
+ |     type: boolean
+ |   - name: s1 = a0
+ |     type: boolean
+ |   - name: v1 = a0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i != a0, a != a0, d != a0, u != a0, b1 != a0, s1 != a0, v1 != a0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i != a0
+ |     type: boolean
+ |   - name: a != a0
+ |     type: boolean
+ |   - name: d != a0
+ |     type: boolean
+ |   - name: u != a0
+ |     type: boolean
+ |   - name: b1 != a0
+ |     type: boolean
+ |   - name: s1 != a0
+ |     type: boolean
+ |   - name: v1 != a0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+
+SELECT d0 > i, d0 > a, d0 > d, d0 > u, d0 > b1, d0 > s1, d0 > v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: d0 > i
+ |     type: boolean
+ |   - name: d0 > a
+ |     type: boolean
+ |   - name: d0 > d
+ |     type: boolean
+ |   - name: d0 > u
+ |     type: boolean
+ |   - name: d0 > b1
+ |     type: boolean
+ |   - name: d0 > s1
+ |     type: boolean
+ |   - name: d0 > v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT d0 < i, d0 < a, d0 < d, d0 < u, d0 < b1, d0 < s1, d0 < v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: d0 < i
+ |     type: boolean
+ |   - name: d0 < a
+ |     type: boolean
+ |   - name: d0 < d
+ |     type: boolean
+ |   - name: d0 < u
+ |     type: boolean
+ |   - name: d0 < b1
+ |     type: boolean
+ |   - name: d0 < s1
+ |     type: boolean
+ |   - name: d0 < v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT d0 >= i, d0 >= a, d0 >= d, d0 >= u, d0 >= b1, d0 >= s1, d0 >= v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: d0 >= i
+ |     type: any
+ |   - name: d0 >= a
+ |     type: any
+ |   - name: d0 >= d
+ |     type: any
+ |   - name: d0 >= u
+ |     type: any
+ |   - name: d0 >= b1
+ |     type: any
+ |   - name: d0 >= s1
+ |     type: any
+ |   - name: d0 >= v1
+ |     type: any
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT d0 <= i, d0 <= a, d0 <= d, d0 <= u, d0 <= b1, d0 <= s1, d0 <= v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: d0 <= i
+ |     type: boolean
+ |   - name: d0 <= a
+ |     type: boolean
+ |   - name: d0 <= d
+ |     type: boolean
+ |   - name: d0 <= u
+ |     type: boolean
+ |   - name: d0 <= b1
+ |     type: boolean
+ |   - name: d0 <= s1
+ |     type: boolean
+ |   - name: d0 <= v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT d0 = i, d0 = a, d0 = d, d0 = u, d0 = b1, d0 = s1, d0 = v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: d0 = i
+ |     type: boolean
+ |   - name: d0 = a
+ |     type: boolean
+ |   - name: d0 = d
+ |     type: boolean
+ |   - name: d0 = u
+ |     type: boolean
+ |   - name: d0 = b1
+ |     type: boolean
+ |   - name: d0 = s1
+ |     type: boolean
+ |   - name: d0 = v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT d0 != i, d0 != a, d0 != d, d0 != u, d0 != b1, d0 != s1, d0 != v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: d0 != i
+ |     type: boolean
+ |   - name: d0 != a
+ |     type: boolean
+ |   - name: d0 != d
+ |     type: boolean
+ |   - name: d0 != u
+ |     type: boolean
+ |   - name: d0 != b1
+ |     type: boolean
+ |   - name: d0 != s1
+ |     type: boolean
+ |   - name: d0 != v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+
+SELECT i > d0, a > d0, d > d0, u > d0, b1 > d0, s1 > d0, v1 > d0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i > d0
+ |     type: boolean
+ |   - name: a > d0
+ |     type: boolean
+ |   - name: d > d0
+ |     type: boolean
+ |   - name: u > d0
+ |     type: boolean
+ |   - name: b1 > d0
+ |     type: boolean
+ |   - name: s1 > d0
+ |     type: boolean
+ |   - name: v1 > d0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i < d0, a < d0, d < d0, u < d0, b1 < d0, s1 < d0, v1 < d0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i < d0
+ |     type: boolean
+ |   - name: a < d0
+ |     type: boolean
+ |   - name: d < d0
+ |     type: boolean
+ |   - name: u < d0
+ |     type: boolean
+ |   - name: b1 < d0
+ |     type: boolean
+ |   - name: s1 < d0
+ |     type: boolean
+ |   - name: v1 < d0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i >= d0, a >= d0, d >= d0, u >= d0, b1 >= d0, s1 >= d0, v1 >= d0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i >= d0
+ |     type: any
+ |   - name: a >= d0
+ |     type: any
+ |   - name: d >= d0
+ |     type: any
+ |   - name: u >= d0
+ |     type: any
+ |   - name: b1 >= d0
+ |     type: any
+ |   - name: s1 >= d0
+ |     type: any
+ |   - name: v1 >= d0
+ |     type: any
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i <= d0, a <= d0, d <= d0, u <= d0, b1 <= d0, s1 <= d0, v1 <= d0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i <= d0
+ |     type: boolean
+ |   - name: a <= d0
+ |     type: boolean
+ |   - name: d <= d0
+ |     type: boolean
+ |   - name: u <= d0
+ |     type: boolean
+ |   - name: b1 <= d0
+ |     type: boolean
+ |   - name: s1 <= d0
+ |     type: boolean
+ |   - name: v1 <= d0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i = d0, a = d0, d = d0, u = d0, b1 = d0, s1 = d0, v1 = d0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i = d0
+ |     type: boolean
+ |   - name: a = d0
+ |     type: boolean
+ |   - name: d = d0
+ |     type: boolean
+ |   - name: u = d0
+ |     type: boolean
+ |   - name: b1 = d0
+ |     type: boolean
+ |   - name: s1 = d0
+ |     type: boolean
+ |   - name: v1 = d0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i != d0, a != d0, d != d0, u != d0, b1 != d0, s1 != d0, v1 != d0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i != d0
+ |     type: boolean
+ |   - name: a != d0
+ |     type: boolean
+ |   - name: d != d0
+ |     type: boolean
+ |   - name: u != d0
+ |     type: boolean
+ |   - name: b1 != d0
+ |     type: boolean
+ |   - name: s1 != d0
+ |     type: boolean
+ |   - name: v1 != d0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+
+SELECT u0 > i, u0 > a, u0 > d, u0 > u, u0 > b1, u0 > s1, u0 > v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: u0 > i
+ |     type: boolean
+ |   - name: u0 > a
+ |     type: boolean
+ |   - name: u0 > d
+ |     type: boolean
+ |   - name: u0 > u
+ |     type: boolean
+ |   - name: u0 > b1
+ |     type: boolean
+ |   - name: u0 > s1
+ |     type: boolean
+ |   - name: u0 > v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT u0 < i, u0 < a, u0 < d, u0 < u, u0 < b1, u0 < s1, u0 < v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: u0 < i
+ |     type: boolean
+ |   - name: u0 < a
+ |     type: boolean
+ |   - name: u0 < d
+ |     type: boolean
+ |   - name: u0 < u
+ |     type: boolean
+ |   - name: u0 < b1
+ |     type: boolean
+ |   - name: u0 < s1
+ |     type: boolean
+ |   - name: u0 < v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT u0 >= i, u0 >= a, u0 >= d, u0 >= u, u0 >= b1, u0 >= s1, u0 >= v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: u0 >= i
+ |     type: any
+ |   - name: u0 >= a
+ |     type: any
+ |   - name: u0 >= d
+ |     type: any
+ |   - name: u0 >= u
+ |     type: any
+ |   - name: u0 >= b1
+ |     type: any
+ |   - name: u0 >= s1
+ |     type: any
+ |   - name: u0 >= v1
+ |     type: any
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT u0 <= i, u0 <= a, u0 <= d, u0 <= u, u0 <= b1, u0 <= s1, u0 <= v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: u0 <= i
+ |     type: boolean
+ |   - name: u0 <= a
+ |     type: boolean
+ |   - name: u0 <= d
+ |     type: boolean
+ |   - name: u0 <= u
+ |     type: boolean
+ |   - name: u0 <= b1
+ |     type: boolean
+ |   - name: u0 <= s1
+ |     type: boolean
+ |   - name: u0 <= v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT u0 = i, u0 = a, u0 = d, u0 = u, u0 = b1, u0 = s1, u0 = v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: u0 = i
+ |     type: boolean
+ |   - name: u0 = a
+ |     type: boolean
+ |   - name: u0 = d
+ |     type: boolean
+ |   - name: u0 = u
+ |     type: boolean
+ |   - name: u0 = b1
+ |     type: boolean
+ |   - name: u0 = s1
+ |     type: boolean
+ |   - name: u0 = v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT u0 != i, u0 != a, u0 != d, u0 != u, u0 != b1, u0 != s1, u0 != v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: u0 != i
+ |     type: boolean
+ |   - name: u0 != a
+ |     type: boolean
+ |   - name: u0 != d
+ |     type: boolean
+ |   - name: u0 != u
+ |     type: boolean
+ |   - name: u0 != b1
+ |     type: boolean
+ |   - name: u0 != s1
+ |     type: boolean
+ |   - name: u0 != v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+
+SELECT i > u0, a > u0, d > u0, u > u0, b1 > u0, s1 > u0, v1 > u0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i > u0
+ |     type: boolean
+ |   - name: a > u0
+ |     type: boolean
+ |   - name: d > u0
+ |     type: boolean
+ |   - name: u > u0
+ |     type: boolean
+ |   - name: b1 > u0
+ |     type: boolean
+ |   - name: s1 > u0
+ |     type: boolean
+ |   - name: v1 > u0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i < u0, a < u0, d < u0, u < u0, b1 < u0, s1 < u0, v1 < u0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i < u0
+ |     type: boolean
+ |   - name: a < u0
+ |     type: boolean
+ |   - name: d < u0
+ |     type: boolean
+ |   - name: u < u0
+ |     type: boolean
+ |   - name: b1 < u0
+ |     type: boolean
+ |   - name: s1 < u0
+ |     type: boolean
+ |   - name: v1 < u0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i >= u0, a >= u0, d >= u0, u >= u0, b1 >= u0, s1 >= u0, v1 >= u0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i >= u0
+ |     type: any
+ |   - name: a >= u0
+ |     type: any
+ |   - name: d >= u0
+ |     type: any
+ |   - name: u >= u0
+ |     type: any
+ |   - name: b1 >= u0
+ |     type: any
+ |   - name: s1 >= u0
+ |     type: any
+ |   - name: v1 >= u0
+ |     type: any
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i <= u0, a <= u0, d <= u0, u <= u0, b1 <= u0, s1 <= u0, v1 <= u0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i <= u0
+ |     type: boolean
+ |   - name: a <= u0
+ |     type: boolean
+ |   - name: d <= u0
+ |     type: boolean
+ |   - name: u <= u0
+ |     type: boolean
+ |   - name: b1 <= u0
+ |     type: boolean
+ |   - name: s1 <= u0
+ |     type: boolean
+ |   - name: v1 <= u0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i = u0, a = u0, d = u0, u = u0, b1 = u0, s1 = u0, v1 = u0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i = u0
+ |     type: boolean
+ |   - name: a = u0
+ |     type: boolean
+ |   - name: d = u0
+ |     type: boolean
+ |   - name: u = u0
+ |     type: boolean
+ |   - name: b1 = u0
+ |     type: boolean
+ |   - name: s1 = u0
+ |     type: boolean
+ |   - name: v1 = u0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i != u0, a != u0, d != u0, u != u0, b1 != u0, s1 != u0, v1 != u0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i != u0
+ |     type: boolean
+ |   - name: a != u0
+ |     type: boolean
+ |   - name: d != u0
+ |     type: boolean
+ |   - name: u != u0
+ |     type: boolean
+ |   - name: b1 != u0
+ |     type: boolean
+ |   - name: s1 != u0
+ |     type: boolean
+ |   - name: v1 != u0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+
+SELECT b0 > i, b0 > a, b0 > d, b0 > u, b0 > b1, b0 > s1, b0 > v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: b0 > i
+ |     type: boolean
+ |   - name: b0 > a
+ |     type: boolean
+ |   - name: b0 > d
+ |     type: boolean
+ |   - name: b0 > u
+ |     type: boolean
+ |   - name: b0 > b1
+ |     type: boolean
+ |   - name: b0 > s1
+ |     type: boolean
+ |   - name: b0 > v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT b0 < i, b0 < a, b0 < d, b0 < u, b0 < b1, b0 < s1, b0 < v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: b0 < i
+ |     type: boolean
+ |   - name: b0 < a
+ |     type: boolean
+ |   - name: b0 < d
+ |     type: boolean
+ |   - name: b0 < u
+ |     type: boolean
+ |   - name: b0 < b1
+ |     type: boolean
+ |   - name: b0 < s1
+ |     type: boolean
+ |   - name: b0 < v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT b0 >= i, b0 >= a, b0 >= d, b0 >= u, b0 >= b1, b0 >= s1, b0 >= v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: b0 >= i
+ |     type: any
+ |   - name: b0 >= a
+ |     type: any
+ |   - name: b0 >= d
+ |     type: any
+ |   - name: b0 >= u
+ |     type: any
+ |   - name: b0 >= b1
+ |     type: any
+ |   - name: b0 >= s1
+ |     type: any
+ |   - name: b0 >= v1
+ |     type: any
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT b0 <= i, b0 <= a, b0 <= d, b0 <= u, b0 <= b1, b0 <= s1, b0 <= v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: b0 <= i
+ |     type: boolean
+ |   - name: b0 <= a
+ |     type: boolean
+ |   - name: b0 <= d
+ |     type: boolean
+ |   - name: b0 <= u
+ |     type: boolean
+ |   - name: b0 <= b1
+ |     type: boolean
+ |   - name: b0 <= s1
+ |     type: boolean
+ |   - name: b0 <= v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT b0 = i, b0 = a, b0 = d, b0 = u, b0 = b1, b0 = s1, b0 = v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: b0 = i
+ |     type: boolean
+ |   - name: b0 = a
+ |     type: boolean
+ |   - name: b0 = d
+ |     type: boolean
+ |   - name: b0 = u
+ |     type: boolean
+ |   - name: b0 = b1
+ |     type: boolean
+ |   - name: b0 = s1
+ |     type: boolean
+ |   - name: b0 = v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT b0 != i, b0 != a, b0 != d, b0 != u, b0 != b1, b0 != s1, b0 != v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: b0 != i
+ |     type: boolean
+ |   - name: b0 != a
+ |     type: boolean
+ |   - name: b0 != d
+ |     type: boolean
+ |   - name: b0 != u
+ |     type: boolean
+ |   - name: b0 != b1
+ |     type: boolean
+ |   - name: b0 != s1
+ |     type: boolean
+ |   - name: b0 != v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+
+SELECT i > b0, a > b0, d > b0, u > b0, b1 > b0, s1 > b0, v1 > b0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i > b0
+ |     type: boolean
+ |   - name: a > b0
+ |     type: boolean
+ |   - name: d > b0
+ |     type: boolean
+ |   - name: u > b0
+ |     type: boolean
+ |   - name: b1 > b0
+ |     type: boolean
+ |   - name: s1 > b0
+ |     type: boolean
+ |   - name: v1 > b0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i < b0, a < b0, d < b0, u < b0, b1 < b0, s1 < b0, v1 < b0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i < b0
+ |     type: boolean
+ |   - name: a < b0
+ |     type: boolean
+ |   - name: d < b0
+ |     type: boolean
+ |   - name: u < b0
+ |     type: boolean
+ |   - name: b1 < b0
+ |     type: boolean
+ |   - name: s1 < b0
+ |     type: boolean
+ |   - name: v1 < b0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i >= b0, a >= b0, d >= b0, u >= b0, b1 >= b0, s1 >= b0, v1 >= b0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i >= b0
+ |     type: any
+ |   - name: a >= b0
+ |     type: any
+ |   - name: d >= b0
+ |     type: any
+ |   - name: u >= b0
+ |     type: any
+ |   - name: b1 >= b0
+ |     type: any
+ |   - name: s1 >= b0
+ |     type: any
+ |   - name: v1 >= b0
+ |     type: any
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i <= b0, a <= b0, d <= b0, u <= b0, b1 <= b0, s1 <= b0, v1 <= b0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i <= b0
+ |     type: boolean
+ |   - name: a <= b0
+ |     type: boolean
+ |   - name: d <= b0
+ |     type: boolean
+ |   - name: u <= b0
+ |     type: boolean
+ |   - name: b1 <= b0
+ |     type: boolean
+ |   - name: s1 <= b0
+ |     type: boolean
+ |   - name: v1 <= b0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i = b0, a = b0, d = b0, u = b0, b1 = b0, s1 = b0, v1 = b0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i = b0
+ |     type: boolean
+ |   - name: a = b0
+ |     type: boolean
+ |   - name: d = b0
+ |     type: boolean
+ |   - name: u = b0
+ |     type: boolean
+ |   - name: b1 = b0
+ |     type: boolean
+ |   - name: s1 = b0
+ |     type: boolean
+ |   - name: v1 = b0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i != b0, a != b0, d != b0, u != b0, b1 != b0, s1 != b0, v1 != b0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i != b0
+ |     type: boolean
+ |   - name: a != b0
+ |     type: boolean
+ |   - name: d != b0
+ |     type: boolean
+ |   - name: u != b0
+ |     type: boolean
+ |   - name: b1 != b0
+ |     type: boolean
+ |   - name: s1 != b0
+ |     type: boolean
+ |   - name: v1 != b0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+
+SELECT s0 > i, s0 > a, s0 > d, s0 > u, s0 > b1, s0 > s1, s0 > v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: s0 > i
+ |     type: boolean
+ |   - name: s0 > a
+ |     type: boolean
+ |   - name: s0 > d
+ |     type: boolean
+ |   - name: s0 > u
+ |     type: boolean
+ |   - name: s0 > b1
+ |     type: boolean
+ |   - name: s0 > s1
+ |     type: boolean
+ |   - name: s0 > v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT s0 < i, s0 < a, s0 < d, s0 < u, s0 < b1, s0 < s1, s0 < v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: s0 < i
+ |     type: boolean
+ |   - name: s0 < a
+ |     type: boolean
+ |   - name: s0 < d
+ |     type: boolean
+ |   - name: s0 < u
+ |     type: boolean
+ |   - name: s0 < b1
+ |     type: boolean
+ |   - name: s0 < s1
+ |     type: boolean
+ |   - name: s0 < v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT s0 >= i, s0 >= a, s0 >= d, s0 >= u, s0 >= b1, s0 >= s1, s0 >= v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: s0 >= i
+ |     type: any
+ |   - name: s0 >= a
+ |     type: any
+ |   - name: s0 >= d
+ |     type: any
+ |   - name: s0 >= u
+ |     type: any
+ |   - name: s0 >= b1
+ |     type: any
+ |   - name: s0 >= s1
+ |     type: any
+ |   - name: s0 >= v1
+ |     type: any
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT s0 <= i, s0 <= a, s0 <= d, s0 <= u, s0 <= b1, s0 <= s1, s0 <= v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: s0 <= i
+ |     type: boolean
+ |   - name: s0 <= a
+ |     type: boolean
+ |   - name: s0 <= d
+ |     type: boolean
+ |   - name: s0 <= u
+ |     type: boolean
+ |   - name: s0 <= b1
+ |     type: boolean
+ |   - name: s0 <= s1
+ |     type: boolean
+ |   - name: s0 <= v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT s0 = i, s0 = a, s0 = d, s0 = u, s0 = b1, s0 = s1, s0 = v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: s0 = i
+ |     type: boolean
+ |   - name: s0 = a
+ |     type: boolean
+ |   - name: s0 = d
+ |     type: boolean
+ |   - name: s0 = u
+ |     type: boolean
+ |   - name: s0 = b1
+ |     type: boolean
+ |   - name: s0 = s1
+ |     type: boolean
+ |   - name: s0 = v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT s0 != i, s0 != a, s0 != d, s0 != u, s0 != b1, s0 != s1, s0 != v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: s0 != i
+ |     type: boolean
+ |   - name: s0 != a
+ |     type: boolean
+ |   - name: s0 != d
+ |     type: boolean
+ |   - name: s0 != u
+ |     type: boolean
+ |   - name: s0 != b1
+ |     type: boolean
+ |   - name: s0 != s1
+ |     type: boolean
+ |   - name: s0 != v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+
+SELECT i > s0, a > s0, d > s0, u > s0, b1 > s0, s1 > s0, v1 > s0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i > s0
+ |     type: boolean
+ |   - name: a > s0
+ |     type: boolean
+ |   - name: d > s0
+ |     type: boolean
+ |   - name: u > s0
+ |     type: boolean
+ |   - name: b1 > s0
+ |     type: boolean
+ |   - name: s1 > s0
+ |     type: boolean
+ |   - name: v1 > s0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i < s0, a < s0, d < s0, u < s0, b1 < s0, s1 < s0, v1 < s0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i < s0
+ |     type: boolean
+ |   - name: a < s0
+ |     type: boolean
+ |   - name: d < s0
+ |     type: boolean
+ |   - name: u < s0
+ |     type: boolean
+ |   - name: b1 < s0
+ |     type: boolean
+ |   - name: s1 < s0
+ |     type: boolean
+ |   - name: v1 < s0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i >= s0, a >= s0, d >= s0, u >= s0, b1 >= s0, s1 >= s0, v1 >= s0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i >= s0
+ |     type: any
+ |   - name: a >= s0
+ |     type: any
+ |   - name: d >= s0
+ |     type: any
+ |   - name: u >= s0
+ |     type: any
+ |   - name: b1 >= s0
+ |     type: any
+ |   - name: s1 >= s0
+ |     type: any
+ |   - name: v1 >= s0
+ |     type: any
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i <= s0, a <= s0, d <= s0, u <= s0, b1 <= s0, s1 <= s0, v1 <= s0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i <= s0
+ |     type: boolean
+ |   - name: a <= s0
+ |     type: boolean
+ |   - name: d <= s0
+ |     type: boolean
+ |   - name: u <= s0
+ |     type: boolean
+ |   - name: b1 <= s0
+ |     type: boolean
+ |   - name: s1 <= s0
+ |     type: boolean
+ |   - name: v1 <= s0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i = s0, a = s0, d = s0, u = s0, b1 = s0, s1 = s0, v1 = s0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i = s0
+ |     type: boolean
+ |   - name: a = s0
+ |     type: boolean
+ |   - name: d = s0
+ |     type: boolean
+ |   - name: u = s0
+ |     type: boolean
+ |   - name: b1 = s0
+ |     type: boolean
+ |   - name: s1 = s0
+ |     type: boolean
+ |   - name: v1 = s0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i != s0, a != s0, d != s0, u != s0, b1 != s0, s1 != s0, v1 != s0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i != s0
+ |     type: boolean
+ |   - name: a != s0
+ |     type: boolean
+ |   - name: d != s0
+ |     type: boolean
+ |   - name: u != s0
+ |     type: boolean
+ |   - name: b1 != s0
+ |     type: boolean
+ |   - name: s1 != s0
+ |     type: boolean
+ |   - name: v1 != s0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+
+SELECT v0 > i, v0 > a, v0 > d, v0 > u, v0 > b1, v0 > s1, v0 > v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: v0 > i
+ |     type: boolean
+ |   - name: v0 > a
+ |     type: boolean
+ |   - name: v0 > d
+ |     type: boolean
+ |   - name: v0 > u
+ |     type: boolean
+ |   - name: v0 > b1
+ |     type: boolean
+ |   - name: v0 > s1
+ |     type: boolean
+ |   - name: v0 > v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT v0 < i, v0 < a, v0 < d, v0 < u, v0 < b1, v0 < s1, v0 < v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: v0 < i
+ |     type: boolean
+ |   - name: v0 < a
+ |     type: boolean
+ |   - name: v0 < d
+ |     type: boolean
+ |   - name: v0 < u
+ |     type: boolean
+ |   - name: v0 < b1
+ |     type: boolean
+ |   - name: v0 < s1
+ |     type: boolean
+ |   - name: v0 < v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT v0 >= i, v0 >= a, v0 >= d, v0 >= u, v0 >= b1, v0 >= s1, v0 >= v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: v0 >= i
+ |     type: any
+ |   - name: v0 >= a
+ |     type: any
+ |   - name: v0 >= d
+ |     type: any
+ |   - name: v0 >= u
+ |     type: any
+ |   - name: v0 >= b1
+ |     type: any
+ |   - name: v0 >= s1
+ |     type: any
+ |   - name: v0 >= v1
+ |     type: any
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT v0 <= i, v0 <= a, v0 <= d, v0 <= u, v0 <= b1, v0 <= s1, v0 <= v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: v0 <= i
+ |     type: boolean
+ |   - name: v0 <= a
+ |     type: boolean
+ |   - name: v0 <= d
+ |     type: boolean
+ |   - name: v0 <= u
+ |     type: boolean
+ |   - name: v0 <= b1
+ |     type: boolean
+ |   - name: v0 <= s1
+ |     type: boolean
+ |   - name: v0 <= v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT v0 = i, v0 = a, v0 = d, v0 = u, v0 = b1, v0 = s1, v0 = v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: v0 = i
+ |     type: boolean
+ |   - name: v0 = a
+ |     type: boolean
+ |   - name: v0 = d
+ |     type: boolean
+ |   - name: v0 = u
+ |     type: boolean
+ |   - name: v0 = b1
+ |     type: boolean
+ |   - name: v0 = s1
+ |     type: boolean
+ |   - name: v0 = v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT v0 != i, v0 != a, v0 != d, v0 != u, v0 != b1, v0 != s1, v0 != v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: v0 != i
+ |     type: boolean
+ |   - name: v0 != a
+ |     type: boolean
+ |   - name: v0 != d
+ |     type: boolean
+ |   - name: v0 != u
+ |     type: boolean
+ |   - name: v0 != b1
+ |     type: boolean
+ |   - name: v0 != s1
+ |     type: boolean
+ |   - name: v0 != v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+
+SELECT i > v0, a > v0, d > v0, u > v0, b1 > v0, s1 > v0, v1 > v0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i > v0
+ |     type: boolean
+ |   - name: a > v0
+ |     type: boolean
+ |   - name: d > v0
+ |     type: boolean
+ |   - name: u > v0
+ |     type: boolean
+ |   - name: b1 > v0
+ |     type: boolean
+ |   - name: s1 > v0
+ |     type: boolean
+ |   - name: v1 > v0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i < v0, a < v0, d < v0, u < v0, b1 < v0, s1 < v0, v1 < v0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i < v0
+ |     type: boolean
+ |   - name: a < v0
+ |     type: boolean
+ |   - name: d < v0
+ |     type: boolean
+ |   - name: u < v0
+ |     type: boolean
+ |   - name: b1 < v0
+ |     type: boolean
+ |   - name: s1 < v0
+ |     type: boolean
+ |   - name: v1 < v0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i >= v0, a >= v0, d >= v0, u >= v0, b1 >= v0, s1 >= v0, v1 >= v0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i >= v0
+ |     type: any
+ |   - name: a >= v0
+ |     type: any
+ |   - name: d >= v0
+ |     type: any
+ |   - name: u >= v0
+ |     type: any
+ |   - name: b1 >= v0
+ |     type: any
+ |   - name: s1 >= v0
+ |     type: any
+ |   - name: v1 >= v0
+ |     type: any
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i <= v0, a <= v0, d <= v0, u <= v0, b1 <= v0, s1 <= v0, v1 <= v0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i <= v0
+ |     type: boolean
+ |   - name: a <= v0
+ |     type: boolean
+ |   - name: d <= v0
+ |     type: boolean
+ |   - name: u <= v0
+ |     type: boolean
+ |   - name: b1 <= v0
+ |     type: boolean
+ |   - name: s1 <= v0
+ |     type: boolean
+ |   - name: v1 <= v0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i = v0, a = v0, d = v0, u = v0, b1 = v0, s1 = v0, v1 = v0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i = v0
+ |     type: boolean
+ |   - name: a = v0
+ |     type: boolean
+ |   - name: d = v0
+ |     type: boolean
+ |   - name: u = v0
+ |     type: boolean
+ |   - name: b1 = v0
+ |     type: boolean
+ |   - name: s1 = v0
+ |     type: boolean
+ |   - name: v1 = v0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i != v0, a != v0, d != v0, u != v0, b1 != v0, s1 != v0, v1 != v0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i != v0
+ |     type: boolean
+ |   - name: a != v0
+ |     type: boolean
+ |   - name: d != v0
+ |     type: boolean
+ |   - name: u != v0
+ |     type: boolean
+ |   - name: b1 != v0
+ |     type: boolean
+ |   - name: s1 != v0
+ |     type: boolean
+ |   - name: v1 != v0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+
+SELECT sc0 > i, sc0 > a, sc0 > d, sc0 > u, sc0 > b1, sc0 > s1, sc0 > v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: sc0 > i
+ |     type: boolean
+ |   - name: sc0 > a
+ |     type: boolean
+ |   - name: sc0 > d
+ |     type: boolean
+ |   - name: sc0 > u
+ |     type: boolean
+ |   - name: sc0 > b1
+ |     type: boolean
+ |   - name: sc0 > s1
+ |     type: boolean
+ |   - name: sc0 > v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT sc0 < i, sc0 < a, sc0 < d, sc0 < u, sc0 < b1, sc0 < s1, sc0 < v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: sc0 < i
+ |     type: boolean
+ |   - name: sc0 < a
+ |     type: boolean
+ |   - name: sc0 < d
+ |     type: boolean
+ |   - name: sc0 < u
+ |     type: boolean
+ |   - name: sc0 < b1
+ |     type: boolean
+ |   - name: sc0 < s1
+ |     type: boolean
+ |   - name: sc0 < v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT sc0 >= i, sc0 >= a, sc0 >= d, sc0 >= u, sc0 >= b1, sc0 >= s1, sc0 >= v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: sc0 >= i
+ |     type: any
+ |   - name: sc0 >= a
+ |     type: any
+ |   - name: sc0 >= d
+ |     type: any
+ |   - name: sc0 >= u
+ |     type: any
+ |   - name: sc0 >= b1
+ |     type: any
+ |   - name: sc0 >= s1
+ |     type: any
+ |   - name: sc0 >= v1
+ |     type: any
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT sc0 <= i, sc0 <= a, sc0 <= d, sc0 <= u, sc0 <= b1, sc0 <= s1, sc0 <= v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: sc0 <= i
+ |     type: boolean
+ |   - name: sc0 <= a
+ |     type: boolean
+ |   - name: sc0 <= d
+ |     type: boolean
+ |   - name: sc0 <= u
+ |     type: boolean
+ |   - name: sc0 <= b1
+ |     type: boolean
+ |   - name: sc0 <= s1
+ |     type: boolean
+ |   - name: sc0 <= v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT sc0 = i, sc0 = a, sc0 = d, sc0 = u, sc0 = b1, sc0 = s1, sc0 = v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: sc0 = i
+ |     type: boolean
+ |   - name: sc0 = a
+ |     type: boolean
+ |   - name: sc0 = d
+ |     type: boolean
+ |   - name: sc0 = u
+ |     type: boolean
+ |   - name: sc0 = b1
+ |     type: boolean
+ |   - name: sc0 = s1
+ |     type: boolean
+ |   - name: sc0 = v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT sc0 != i, sc0 != a, sc0 != d, sc0 != u, sc0 != b1, sc0 != s1, sc0 != v1 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: sc0 != i
+ |     type: boolean
+ |   - name: sc0 != a
+ |     type: boolean
+ |   - name: sc0 != d
+ |     type: boolean
+ |   - name: sc0 != u
+ |     type: boolean
+ |   - name: sc0 != b1
+ |     type: boolean
+ |   - name: sc0 != s1
+ |     type: boolean
+ |   - name: sc0 != v1
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+
+SELECT i > sc0, a > sc0, d > sc0, u > sc0, b1 > sc0, s1 > sc0, v1 > sc0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i > sc0
+ |     type: boolean
+ |   - name: a > sc0
+ |     type: boolean
+ |   - name: d > sc0
+ |     type: boolean
+ |   - name: u > sc0
+ |     type: boolean
+ |   - name: b1 > sc0
+ |     type: boolean
+ |   - name: s1 > sc0
+ |     type: boolean
+ |   - name: v1 > sc0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i < sc0, a < sc0, d < sc0, u < sc0, b1 < sc0, s1 < sc0, v1 < sc0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i < sc0
+ |     type: boolean
+ |   - name: a < sc0
+ |     type: boolean
+ |   - name: d < sc0
+ |     type: boolean
+ |   - name: u < sc0
+ |     type: boolean
+ |   - name: b1 < sc0
+ |     type: boolean
+ |   - name: s1 < sc0
+ |     type: boolean
+ |   - name: v1 < sc0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i >= sc0, a >= sc0, d >= sc0, u >= sc0, b1 >= sc0, s1 >= sc0, v1 >= sc0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i >= sc0
+ |     type: any
+ |   - name: a >= sc0
+ |     type: any
+ |   - name: d >= sc0
+ |     type: any
+ |   - name: u >= sc0
+ |     type: any
+ |   - name: b1 >= sc0
+ |     type: any
+ |   - name: s1 >= sc0
+ |     type: any
+ |   - name: v1 >= sc0
+ |     type: any
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i <= sc0, a <= sc0, d <= sc0, u <= sc0, b1 <= sc0, s1 <= sc0, v1 <= sc0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i <= sc0
+ |     type: boolean
+ |   - name: a <= sc0
+ |     type: boolean
+ |   - name: d <= sc0
+ |     type: boolean
+ |   - name: u <= sc0
+ |     type: boolean
+ |   - name: b1 <= sc0
+ |     type: boolean
+ |   - name: s1 <= sc0
+ |     type: boolean
+ |   - name: v1 <= sc0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i = sc0, a = sc0, d = sc0, u = sc0, b1 = sc0, s1 = sc0, v1 = sc0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i = sc0
+ |     type: boolean
+ |   - name: a = sc0
+ |     type: boolean
+ |   - name: d = sc0
+ |     type: boolean
+ |   - name: u = sc0
+ |     type: boolean
+ |   - name: b1 = sc0
+ |     type: boolean
+ |   - name: s1 = sc0
+ |     type: boolean
+ |   - name: v1 = sc0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+SELECT i != sc0, a != sc0, d != sc0, u != sc0, b1 != sc0, s1 != sc0, v1 != sc0 FROM t0, tn, tb, ts, tv;
+ | ---
+ | - metadata:
+ |   - name: i != sc0
+ |     type: boolean
+ |   - name: a != sc0
+ |     type: boolean
+ |   - name: d != sc0
+ |     type: boolean
+ |   - name: u != sc0
+ |     type: boolean
+ |   - name: b1 != sc0
+ |     type: boolean
+ |   - name: s1 != sc0
+ |     type: boolean
+ |   - name: v1 != sc0
+ |     type: boolean
+ |   rows:
+ |   - [null, null, null, null, null, null, null]
+ |   - [null, null, null, null, null, null, null]
+ | ...
+
+-- Make sure that numbers cannot be compared with BOOLEAN values.
+SELECT 3 > true;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT 3 < true;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT 3 >= true;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT 3 <= true;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT 3 = true;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT 3 != true;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+
+SELECT true > 4;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT true < 4;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT true >= 4;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT true <= 4;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT true = 4;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT true != 4;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+
+SELECT 3.5 > true;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to real'
+ | ...
+SELECT 3.5 < true;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to real'
+ | ...
+SELECT 3.5 >= true;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to real'
+ | ...
+SELECT 3.5 <= true;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to real'
+ | ...
+SELECT 3.5 = true;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to real'
+ | ...
+SELECT 3.5 != true;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to real'
+ | ...
+
+SELECT true > 0.5;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to boolean'
+ | ...
+SELECT true < 0.5;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to boolean'
+ | ...
+SELECT true >= 0.5;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to boolean'
+ | ...
+SELECT true <= 0.5;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to boolean'
+ | ...
+SELECT true = 0.5;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to boolean'
+ | ...
+SELECT true != 0.5;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to boolean'
+ | ...
+
+SELECT i > true FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT i < true FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT i >= true FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT i <= true FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT i = true FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT i != true FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+
+SELECT true > i FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT true < i FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT true >= i FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT true <= i FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT true = i FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT true != i FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+
+SELECT a > true FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT a < true FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT a >= true FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT a <= true FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT a = true FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT a != true FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+
+SELECT true > a FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT true < a FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT true >= a FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT true <= a FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT true = a FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT true != a FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+
+SELECT d > true FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to real'
+ | ...
+SELECT d < true FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to real'
+ | ...
+SELECT d >= true FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to real'
+ | ...
+SELECT d <= true FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to real'
+ | ...
+SELECT d = true FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to real'
+ | ...
+SELECT d != true FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to real'
+ | ...
+
+SELECT true > d FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to boolean'
+ | ...
+SELECT true < d FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to boolean'
+ | ...
+SELECT true >= d FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to boolean'
+ | ...
+SELECT true <= d FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to boolean'
+ | ...
+SELECT true = d FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to boolean'
+ | ...
+SELECT true != d FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to boolean'
+ | ...
+
+SELECT u > true FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT u < true FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT u >= true FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT u <= true FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT u = true FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT u != true FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+
+SELECT true > u FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT true < u FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT true >= u FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT true <= u FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT true = u FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT true != u FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+
+SELECT 3 > b1 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT 3 < b1 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT 3 >= b1 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT 3 <= b1 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT 3 = b1 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT 3 != b1 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+
+SELECT b1 > 4 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT b1 < 4 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT b1 >= 4 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT b1 <= 4 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT b1 = 4 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT b1 != 4 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+
+SELECT 3.5 > b1 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to real'
+ | ...
+SELECT 3.5 < b1 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to real'
+ | ...
+SELECT 3.5 >= b1 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to real'
+ | ...
+SELECT 3.5 <= b1 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to real'
+ | ...
+SELECT 3.5 = b1 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to real'
+ | ...
+SELECT 3.5 != b1 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to real'
+ | ...
+
+SELECT b1 > 0.5 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to boolean'
+ | ...
+SELECT b1 < 0.5 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to boolean'
+ | ...
+SELECT b1 >= 0.5 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to boolean'
+ | ...
+SELECT b1 <= 0.5 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to boolean'
+ | ...
+SELECT b1 = 0.5 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to boolean'
+ | ...
+SELECT b1 != 0.5 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to boolean'
+ | ...
+
+SELECT i > b1 FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT i < b1 FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT i >= b1 FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT i <= b1 FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT i = b1 FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT i != b1 FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+
+SELECT b1 > i FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT b1 < i FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT b1 >= i FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT b1 <= i FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT b1 = i FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT b1 != i FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+
+SELECT a > b1 FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT a < b1 FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT a >= b1 FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT a <= b1 FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT a = b1 FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT a != b1 FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+
+SELECT b1 > a FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT b1 < a FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT b1 >= a FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT b1 <= a FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT b1 = a FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT b1 != a FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+
+SELECT d > b1 FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to real'
+ | ...
+SELECT d < b1 FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to real'
+ | ...
+SELECT d >= b1 FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to real'
+ | ...
+SELECT d <= b1 FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to real'
+ | ...
+SELECT d = b1 FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to real'
+ | ...
+SELECT d != b1 FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to real'
+ | ...
+
+SELECT b1 > d FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to boolean'
+ | ...
+SELECT b1 < d FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to boolean'
+ | ...
+SELECT b1 >= d FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to boolean'
+ | ...
+SELECT b1 <= d FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to boolean'
+ | ...
+SELECT b1 = d FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to boolean'
+ | ...
+SELECT b1 != d FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to boolean'
+ | ...
+
+SELECT u > b1 FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT u < b1 FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT u >= b1 FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT u <= b1 FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT u = b1 FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+SELECT u != b1 FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to unsigned'
+ | ...
+
+SELECT b1 > u FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT b1 < u FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT b1 >= u FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT b1 <= u FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT b1 = u FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+SELECT b1 != u FROM tn, tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to boolean'
+ | ...
+
+-- Make sure that numbers cannot be compared with STRING values.
+SELECT 3 > '123';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT 3 < '123';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT 3 >= '123';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT 3 <= '123';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT 3 = '123';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT 3 != '123';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+
+SELECT '123' > 4;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT '123' < 4;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT '123' >= 4;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT '123' <= 4;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT '123' = 4;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT '123' != 4;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+
+SELECT 3.5 > '123';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to real'
+ | ...
+SELECT 3.5 < '123';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to real'
+ | ...
+SELECT 3.5 >= '123';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to real'
+ | ...
+SELECT 3.5 <= '123';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to real'
+ | ...
+SELECT 3.5 = '123';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to real'
+ | ...
+SELECT 3.5 != '123';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to real'
+ | ...
+
+SELECT '123' > 0.5;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to text'
+ | ...
+SELECT '123' < 0.5;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to text'
+ | ...
+SELECT '123' >= 0.5;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to text'
+ | ...
+SELECT '123' <= 0.5;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to text'
+ | ...
+SELECT '123' = 0.5;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to text'
+ | ...
+SELECT '123' != 0.5;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to text'
+ | ...
+
+SELECT i > '123' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT i < '123' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT i >= '123' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT i <= '123' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT i = '123' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT i != '123' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+
+SELECT '123' > i FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT '123' < i FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT '123' >= i FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT '123' <= i FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT '123' = i FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT '123' != i FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+
+SELECT a > '123' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT a < '123' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT a >= '123' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT a <= '123' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT a = '123' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT a != '123' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+
+SELECT '123' > a FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT '123' < a FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT '123' >= a FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT '123' <= a FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT '123' = a FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT '123' != a FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+
+SELECT d > '123' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to real'
+ | ...
+SELECT d < '123' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to real'
+ | ...
+SELECT d >= '123' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to real'
+ | ...
+SELECT d <= '123' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to real'
+ | ...
+SELECT d = '123' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to real'
+ | ...
+SELECT d != '123' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to real'
+ | ...
+
+SELECT '123' > d FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to text'
+ | ...
+SELECT '123' < d FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to text'
+ | ...
+SELECT '123' >= d FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to text'
+ | ...
+SELECT '123' <= d FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to text'
+ | ...
+SELECT '123' = d FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to text'
+ | ...
+SELECT '123' != d FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to text'
+ | ...
+
+SELECT u > '123' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT u < '123' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT u >= '123' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT u <= '123' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT u = '123' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT u != '123' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+
+SELECT '123' > u FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT '123' < u FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT '123' >= u FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT '123' <= u FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT '123' = u FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT '123' != u FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+
+SELECT 3 > s1 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT 3 < s1 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT 3 >= s1 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT 3 <= s1 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT 3 = s1 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT 3 != s1 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+
+SELECT s1 > 4 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT s1 < 4 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT s1 >= 4 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT s1 <= 4 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT s1 = 4 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT s1 != 4 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+
+SELECT 3.5 > s1 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to real'
+ | ...
+SELECT 3.5 < s1 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to real'
+ | ...
+SELECT 3.5 >= s1 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to real'
+ | ...
+SELECT 3.5 <= s1 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to real'
+ | ...
+SELECT 3.5 = s1 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to real'
+ | ...
+SELECT 3.5 != s1 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to real'
+ | ...
+
+SELECT s1 > 0.5 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to text'
+ | ...
+SELECT s1 < 0.5 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to text'
+ | ...
+SELECT s1 >= 0.5 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to text'
+ | ...
+SELECT s1 <= 0.5 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to text'
+ | ...
+SELECT s1 = 0.5 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to text'
+ | ...
+SELECT s1 != 0.5 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to text'
+ | ...
+
+SELECT i > s1 FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT i < s1 FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT i >= s1 FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT i <= s1 FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT i = s1 FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT i != s1 FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+
+SELECT s1 > i FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT s1 < i FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT s1 >= i FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT s1 <= i FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT s1 = i FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT s1 != i FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+
+SELECT a > s1 FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT a < s1 FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT a >= s1 FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT a <= s1 FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT a = s1 FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT a != s1 FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+
+SELECT s1 > a FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT s1 < a FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT s1 >= a FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT s1 <= a FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT s1 = a FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT s1 != a FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+
+SELECT d > s1 FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to real'
+ | ...
+SELECT d < s1 FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to real'
+ | ...
+SELECT d >= s1 FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to real'
+ | ...
+SELECT d <= s1 FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to real'
+ | ...
+SELECT d = s1 FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to real'
+ | ...
+SELECT d != s1 FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to real'
+ | ...
+
+SELECT s1 > d FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to text'
+ | ...
+SELECT s1 < d FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to text'
+ | ...
+SELECT s1 >= d FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to text'
+ | ...
+SELECT s1 <= d FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to text'
+ | ...
+SELECT s1 = d FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to text'
+ | ...
+SELECT s1 != d FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to text'
+ | ...
+
+SELECT u > s1 FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT u < s1 FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT u >= s1 FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT u <= s1 FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT u = s1 FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+SELECT u != s1 FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to unsigned'
+ | ...
+
+SELECT s1 > u FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT s1 < u FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT s1 >= u FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT s1 <= u FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT s1 = u FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+SELECT s1 != u FROM tn, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to text'
+ | ...
+
+--
+-- Make sure that numbers cannot be compared with VARBINARY
+-- values.
+--
+SELECT 3 > X'3139';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT 3 < X'3139';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT 3 >= X'3139';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT 3 <= X'3139';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT 3 = X'3139';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT 3 != X'3139';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+
+SELECT X'3139' > 4;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT X'3139' < 4;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT X'3139' >= 4;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT X'3139' <= 4;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT X'3139' = 4;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT X'3139' != 4;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+
+SELECT 3.5 > X'3139';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to real'
+ | ...
+SELECT 3.5 < X'3139';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to real'
+ | ...
+SELECT 3.5 >= X'3139';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to real'
+ | ...
+SELECT 3.5 <= X'3139';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to real'
+ | ...
+SELECT 3.5 = X'3139';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to real'
+ | ...
+SELECT 3.5 != X'3139';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to real'
+ | ...
+
+SELECT X'3139' > 0.5;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to varbinary'
+ | ...
+SELECT X'3139' < 0.5;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to varbinary'
+ | ...
+SELECT X'3139' >= 0.5;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to varbinary'
+ | ...
+SELECT X'3139' <= 0.5;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to varbinary'
+ | ...
+SELECT X'3139' = 0.5;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to varbinary'
+ | ...
+SELECT X'3139' != 0.5;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to varbinary'
+ | ...
+
+SELECT i > X'3139' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT i < X'3139' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT i >= X'3139' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT i <= X'3139' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT i = X'3139' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT i != X'3139' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+
+SELECT X'3139' > i FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT X'3139' < i FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT X'3139' >= i FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT X'3139' <= i FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT X'3139' = i FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT X'3139' != i FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+
+SELECT a > X'3139' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT a < X'3139' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT a >= X'3139' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT a <= X'3139' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT a = X'3139' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT a != X'3139' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+
+SELECT X'3139' > a FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT X'3139' < a FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT X'3139' >= a FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT X'3139' <= a FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT X'3139' = a FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT X'3139' != a FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+
+SELECT d > X'3139' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to real'
+ | ...
+SELECT d < X'3139' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to real'
+ | ...
+SELECT d >= X'3139' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to real'
+ | ...
+SELECT d <= X'3139' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to real'
+ | ...
+SELECT d = X'3139' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to real'
+ | ...
+SELECT d != X'3139' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to real'
+ | ...
+
+SELECT X'3139' > d FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to varbinary'
+ | ...
+SELECT X'3139' < d FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to varbinary'
+ | ...
+SELECT X'3139' >= d FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to varbinary'
+ | ...
+SELECT X'3139' <= d FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to varbinary'
+ | ...
+SELECT X'3139' = d FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to varbinary'
+ | ...
+SELECT X'3139' != d FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to varbinary'
+ | ...
+
+SELECT u > X'3139' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT u < X'3139' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT u >= X'3139' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT u <= X'3139' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT u = X'3139' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT u != X'3139' FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+
+SELECT X'3139' > u FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT X'3139' < u FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT X'3139' >= u FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT X'3139' <= u FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT X'3139' = u FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT X'3139' != u FROM tn;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+
+SELECT 3 > v1 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT 3 < v1 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT 3 >= v1 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT 3 <= v1 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT 3 = v1 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT 3 != v1 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+
+SELECT v1 > 4 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT v1 < 4 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT v1 >= 4 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT v1 <= 4 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT v1 = 4 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT v1 != 4 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+
+SELECT 3.5 > v1 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to real'
+ | ...
+SELECT 3.5 < v1 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to real'
+ | ...
+SELECT 3.5 >= v1 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to real'
+ | ...
+SELECT 3.5 <= v1 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to real'
+ | ...
+SELECT 3.5 = v1 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to real'
+ | ...
+SELECT 3.5 != v1 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to real'
+ | ...
+
+SELECT v1 > 0.5 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to varbinary'
+ | ...
+SELECT v1 < 0.5 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to varbinary'
+ | ...
+SELECT v1 >= 0.5 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to varbinary'
+ | ...
+SELECT v1 <= 0.5 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to varbinary'
+ | ...
+SELECT v1 = 0.5 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to varbinary'
+ | ...
+SELECT v1 != 0.5 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to varbinary'
+ | ...
+
+SELECT i > v1 FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT i < v1 FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT i >= v1 FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT i <= v1 FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT i = v1 FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT i != v1 FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+
+SELECT v1 > i FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT v1 < i FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT v1 >= i FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT v1 <= i FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT v1 = i FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT v1 != i FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+
+SELECT a > v1 FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT a < v1 FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT a >= v1 FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT a <= v1 FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT a = v1 FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT a != v1 FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+
+SELECT v1 > a FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT v1 < a FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT v1 >= a FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT v1 <= a FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT v1 = a FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT v1 != a FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+
+SELECT d > v1 FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to real'
+ | ...
+SELECT d < v1 FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to real'
+ | ...
+SELECT d >= v1 FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to real'
+ | ...
+SELECT d <= v1 FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to real'
+ | ...
+SELECT d = v1 FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to real'
+ | ...
+SELECT d != v1 FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to real'
+ | ...
+
+SELECT v1 > d FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to varbinary'
+ | ...
+SELECT v1 < d FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to varbinary'
+ | ...
+SELECT v1 >= d FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to varbinary'
+ | ...
+SELECT v1 <= d FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to varbinary'
+ | ...
+SELECT v1 = d FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to varbinary'
+ | ...
+SELECT v1 != d FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert real to varbinary'
+ | ...
+
+SELECT u > v1 FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT u < v1 FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT u >= v1 FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT u <= v1 FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT u = v1 FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+SELECT u != v1 FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to unsigned'
+ | ...
+
+SELECT v1 > u FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT v1 < u FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT v1 >= u FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT v1 <= u FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT v1 = u FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+SELECT v1 != u FROM tn, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert unsigned to varbinary'
+ | ...
+
+--
+-- Make sure that BOOLEAN values cannot be compared with STRING
+-- values.
+--
+SELECT true > 'TRUE';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to boolean'
+ | ...
+SELECT true < 'TRUE';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to boolean'
+ | ...
+SELECT true >= 'TRUE';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to boolean'
+ | ...
+SELECT true <= 'TRUE';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to boolean'
+ | ...
+SELECT true = 'TRUE';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to boolean'
+ | ...
+SELECT true != 'TRUE';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to boolean'
+ | ...
+
+SELECT 'TRUE' > true;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to text'
+ | ...
+SELECT 'TRUE' < true;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to text'
+ | ...
+SELECT 'TRUE' >= true;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to text'
+ | ...
+SELECT 'TRUE' <= true;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to text'
+ | ...
+SELECT 'TRUE' = true;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to text'
+ | ...
+SELECT 'TRUE' != true;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to text'
+ | ...
+
+SELECT b1 > 'TRUE' FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to boolean'
+ | ...
+SELECT b1 < 'TRUE' FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to boolean'
+ | ...
+SELECT b1 >= 'TRUE' FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to boolean'
+ | ...
+SELECT b1 <= 'TRUE' FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to boolean'
+ | ...
+SELECT b1 = 'TRUE' FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to boolean'
+ | ...
+SELECT b1 != 'TRUE' FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to boolean'
+ | ...
+
+SELECT 'TRUE' > b1 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to text'
+ | ...
+SELECT 'TRUE' < b1 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to text'
+ | ...
+SELECT 'TRUE' >= b1 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to text'
+ | ...
+SELECT 'TRUE' <= b1 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to text'
+ | ...
+SELECT 'TRUE' = b1 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to text'
+ | ...
+SELECT 'TRUE' != b1 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to text'
+ | ...
+
+SELECT true > s1 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to boolean'
+ | ...
+SELECT true < s1 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to boolean'
+ | ...
+SELECT true >= s1 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to boolean'
+ | ...
+SELECT true <= s1 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to boolean'
+ | ...
+SELECT true = s1 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to boolean'
+ | ...
+SELECT true != s1 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to boolean'
+ | ...
+
+SELECT s1 > true FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to text'
+ | ...
+SELECT s1 < true FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to text'
+ | ...
+SELECT s1 >= true FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to text'
+ | ...
+SELECT s1 <= true FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to text'
+ | ...
+SELECT s1 = true FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to text'
+ | ...
+SELECT s1 != true FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to text'
+ | ...
+
+SELECT b1 > s1 FROM tb, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to boolean'
+ | ...
+SELECT b1 < s1 FROM tb, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to boolean'
+ | ...
+SELECT b1 >= s1 FROM tb, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to boolean'
+ | ...
+SELECT b1 <= s1 FROM tb, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to boolean'
+ | ...
+SELECT b1 = s1 FROM tb, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to boolean'
+ | ...
+SELECT b1 != s1 FROM tb, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to boolean'
+ | ...
+
+SELECT s1 > b1 FROM tb, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to text'
+ | ...
+SELECT s1 < b1 FROM tb, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to text'
+ | ...
+SELECT s1 >= b1 FROM tb, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to text'
+ | ...
+SELECT s1 <= b1 FROM tb, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to text'
+ | ...
+SELECT s1 = b1 FROM tb, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to text'
+ | ...
+SELECT s1 != b1 FROM tb, ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to text'
+ | ...
+
+--
+-- Make sure that BOOLEAN values cannot be compared with VARBINARY
+-- values.
+--
+SELECT true > X'54525545';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to boolean'
+ | ...
+SELECT true < X'54525545';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to boolean'
+ | ...
+SELECT true >= X'54525545';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to boolean'
+ | ...
+SELECT true <= X'54525545';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to boolean'
+ | ...
+SELECT true = X'54525545';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to boolean'
+ | ...
+SELECT true != X'54525545';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to boolean'
+ | ...
+
+SELECT X'54525545' > true;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to varbinary'
+ | ...
+SELECT X'54525545' < true;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to varbinary'
+ | ...
+SELECT X'54525545' >= true;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to varbinary'
+ | ...
+SELECT X'54525545' <= true;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to varbinary'
+ | ...
+SELECT X'54525545' = true;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to varbinary'
+ | ...
+SELECT X'54525545' != true;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to varbinary'
+ | ...
+
+SELECT b1 > X'54525545' FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to boolean'
+ | ...
+SELECT b1 < X'54525545' FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to boolean'
+ | ...
+SELECT b1 >= X'54525545' FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to boolean'
+ | ...
+SELECT b1 <= X'54525545' FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to boolean'
+ | ...
+SELECT b1 = X'54525545' FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to boolean'
+ | ...
+SELECT b1 != X'54525545' FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to boolean'
+ | ...
+
+SELECT X'54525545' > b1 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to varbinary'
+ | ...
+SELECT X'54525545' < b1 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to varbinary'
+ | ...
+SELECT X'54525545' >= b1 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to varbinary'
+ | ...
+SELECT X'54525545' <= b1 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to varbinary'
+ | ...
+SELECT X'54525545' = b1 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to varbinary'
+ | ...
+SELECT X'54525545' != b1 FROM tb;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to varbinary'
+ | ...
+
+DELETE FROM tv;
+ | ---
+ | - row_count: 1
+ | ...
+INSERT INTO tv VALUES (X'54525545', X'54525545');
+ | ---
+ | - row_count: 1
+ | ...
+
+SELECT true > v1 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to boolean'
+ | ...
+SELECT true < v1 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to boolean'
+ | ...
+SELECT true >= v1 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to boolean'
+ | ...
+SELECT true <= v1 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to boolean'
+ | ...
+SELECT true = v1 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to boolean'
+ | ...
+SELECT true != v1 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to boolean'
+ | ...
+
+SELECT v1 > true FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to varbinary'
+ | ...
+SELECT v1 < true FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to varbinary'
+ | ...
+SELECT v1 >= true FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to varbinary'
+ | ...
+SELECT v1 <= true FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to varbinary'
+ | ...
+SELECT v1 = true FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to varbinary'
+ | ...
+SELECT v1 != true FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to varbinary'
+ | ...
+
+SELECT b1 > v1 FROM tb, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to boolean'
+ | ...
+SELECT b1 < v1 FROM tb, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to boolean'
+ | ...
+SELECT b1 >= v1 FROM tb, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to boolean'
+ | ...
+SELECT b1 <= v1 FROM tb, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to boolean'
+ | ...
+SELECT b1 = v1 FROM tb, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to boolean'
+ | ...
+SELECT b1 != v1 FROM tb, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to boolean'
+ | ...
+
+SELECT v1 > b1 FROM tb, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to varbinary'
+ | ...
+SELECT v1 < b1 FROM tb, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to varbinary'
+ | ...
+SELECT v1 >= b1 FROM tb, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to varbinary'
+ | ...
+SELECT v1 <= b1 FROM tb, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to varbinary'
+ | ...
+SELECT v1 = b1 FROM tb, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to varbinary'
+ | ...
+SELECT v1 != b1 FROM tb, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert boolean to varbinary'
+ | ...
+
+--
+-- Make sure that STRING values cannot be compared with VARBINARY
+-- values.
+--
+SELECT '123' > X'54525545';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to text'
+ | ...
+SELECT '123' < X'54525545';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to text'
+ | ...
+SELECT '123' >= X'54525545';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to text'
+ | ...
+SELECT '123' <= X'54525545';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to text'
+ | ...
+SELECT '123' = X'54525545';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to text'
+ | ...
+SELECT '123' != X'54525545';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to text'
+ | ...
+
+SELECT X'54525545' > '123';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to varbinary'
+ | ...
+SELECT X'54525545' < '123';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to varbinary'
+ | ...
+SELECT X'54525545' >= '123';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to varbinary'
+ | ...
+SELECT X'54525545' <= '123';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to varbinary'
+ | ...
+SELECT X'54525545' = '123';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to varbinary'
+ | ...
+SELECT X'54525545' != '123';
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to varbinary'
+ | ...
+
+SELECT s1 > X'54525545' FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to text'
+ | ...
+SELECT s1 < X'54525545' FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to text'
+ | ...
+SELECT s1 >= X'54525545' FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to text'
+ | ...
+SELECT s1 <= X'54525545' FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to text'
+ | ...
+SELECT s1 = X'54525545' FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to text'
+ | ...
+SELECT s1 != X'54525545' FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to text'
+ | ...
+
+SELECT X'54525545' > s1 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to varbinary'
+ | ...
+SELECT X'54525545' < s1 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to varbinary'
+ | ...
+SELECT X'54525545' >= s1 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to varbinary'
+ | ...
+SELECT X'54525545' <= s1 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to varbinary'
+ | ...
+SELECT X'54525545' = s1 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to varbinary'
+ | ...
+SELECT X'54525545' != s1 FROM ts;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to varbinary'
+ | ...
+
+SELECT '123' > v1 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to text'
+ | ...
+SELECT '123' < v1 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to text'
+ | ...
+SELECT '123' >= v1 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to text'
+ | ...
+SELECT '123' <= v1 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to text'
+ | ...
+SELECT '123' = v1 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to text'
+ | ...
+SELECT '123' != v1 FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to text'
+ | ...
+
+SELECT v1 > '123' FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to varbinary'
+ | ...
+SELECT v1 < '123' FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to varbinary'
+ | ...
+SELECT v1 >= '123' FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to varbinary'
+ | ...
+SELECT v1 <= '123' FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to varbinary'
+ | ...
+SELECT v1 = '123' FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to varbinary'
+ | ...
+SELECT v1 != '123' FROM tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to varbinary'
+ | ...
+
+SELECT s1 > v1 FROM ts, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to text'
+ | ...
+SELECT s1 < v1 FROM ts, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to text'
+ | ...
+SELECT s1 >= v1 FROM ts, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to text'
+ | ...
+SELECT s1 <= v1 FROM ts, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to text'
+ | ...
+SELECT s1 = v1 FROM ts, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to text'
+ | ...
+SELECT s1 != v1 FROM ts, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert varbinary to text'
+ | ...
+
+SELECT v1 > s1 FROM ts, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to varbinary'
+ | ...
+SELECT v1 < s1 FROM ts, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to varbinary'
+ | ...
+SELECT v1 >= s1 FROM ts, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to varbinary'
+ | ...
+SELECT v1 <= s1 FROM ts, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to varbinary'
+ | ...
+SELECT v1 = s1 FROM ts, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to varbinary'
+ | ...
+SELECT v1 != s1 FROM ts, tv;
+ | ---
+ | - null
+ | - 'Type mismatch: can not convert text to varbinary'
+ | ...
diff --git a/test/sql/gh-4230-remove-implicit-cast-for-comparison.test.sql b/test/sql/gh-4230-remove-implicit-cast-for-comparison.test.sql
new file mode 100644
index 0000000..f8cc29f
--- /dev/null
+++ b/test/sql/gh-4230-remove-implicit-cast-for-comparison.test.sql
@@ -0,0 +1,953 @@
+-- Make sure that comparison between numeric types works.
+SELECT 2 > 1, 1.5 > 1, 2.5 > 1.5;
+SELECT 2 < 1, 1.5 < 1, 2.5 < 1.5;
+SELECT 2 >= 1, 1.5 >= 1, 2.5 >= 1.5;
+SELECT 2 <= 1, 1.5 <= 1, 2.5 <= 1.5;
+SELECT 2 = 1, 1.5 = 1, 2.5 = 1.5;
+SELECT 2 != 1, 1.5 != 1, 2.5 != 1.5;
+
+CREATE TABLE tn(i INT PRIMARY KEY, a NUMBER, d DOUBLE, u UNSIGNED);
+INSERT INTO tn VALUES (1, 2, 3.3, 4);
+INSERT INTO tn VALUES (2, 3.5, 3, 4);
+SELECT i > 1, i > 1.5, a > 1, a > 1.5, d > 1, d > 1.5, u > 1, u > 1.5 FROM tn;
+SELECT i < 1, i < 1.5, a < 1, a < 1.5, d < 1, d < 1.5, u < 1, u < 1.5 FROM tn;
+SELECT i >= 1, i >= 1.5, a >= 1, a >= 1.5, d >= 1, d >= 1.5, u >= 1, u >= 1.5 FROM tn;
+SELECT i <= 1, i <= 1.5, a <= 1, a <= 1.5, d <= 1, d <= 1.5, u <= 1, u <= 1.5 FROM tn;
+SELECT i = 1, i = 1.5, a = 1, a = 1.5, d = 1, d = 1.5, u = 1, u = 1.5 FROM tn;
+SELECT i != 1, i != 1.5, a != 1, a != 1.5, d != 1, d != 1.5, u != 1, u != 1.5 FROM tn;
+
+SELECT 1 > i, 1.5 > i, 1 > a, 1.5 > a, 1 > d, 1.5 > d, 1 > u, 1.5 > u FROM tn;
+SELECT 1 < i, 1.5 < i, 1 < a, 1.5 < a, 1 < d, 1.5 < d, 1 < u, 1.5 < u FROM tn;
+SELECT 1 >= i, 1.5 >= i, 1 >= a, 1.5 >= a, 1 >= d, 1.5 >= d, 1 >= u, 1.5 >= u FROM tn;
+SELECT 1 <= i, 1.5 <= i, 1 <= a, 1.5 <= a, 1 <= d, 1.5 <= d, 1 <= u, 1.5 <= u FROM tn;
+SELECT 1 = i, 1.5 = i, 1 = a, 1.5 = a, 1 = d, 1.5 = d, 1 = u, 1.5 = u FROM tn;
+SELECT 1 != i, 1.5 != i, 1 != a, 1.5 != a, 1 != d, 1.5 != d, 1 != u, 1.5 != u FROM tn;
+
+SELECT i > i, i > a, i > d, i > u, a > a, a > d, a > u, d > d, d > u, u > u FROM tn;
+SELECT i < i, i < a, i < d, i < u, a < a, a < d, a < u, d < d, d < u, u < u FROM tn;
+SELECT i >= i, i >= a, i >= d, i >= u, a >= a, a >= d, a >= u, d >= d, d >= u, u >= u FROM tn;
+SELECT i <= i, i <= a, i <= d, i <= u, a <= a, a <= d, a <= u, d <= d, d <= u, u <= u FROM tn;
+SELECT i = i, i = a, i = d, i = u, a = a, a = d, a = u, d = d, d = u, u = u FROM tn;
+SELECT i != i, i != a, i != d, i != u, a != a, a != d, a != u, d != d, d != u, u != u FROM tn;
+
+-- Make sure that comparison between BOOLEAN values works.
+SELECT true > false;
+SELECT true < false;
+SELECT true >= false;
+SELECT true <= false;
+SELECT true = false;
+SELECT true != false;
+
+CREATE TABLE tb(b1 BOOLEAN PRIMARY KEY, b2 BOOLEAN);
+INSERT INTO tb VALUES (true, false);
+SELECT b1 > true FROM tb;
+SELECT b1 < true FROM tb;
+SELECT b1 >= true FROM tb;
+SELECT b1 <= true FROM tb;
+SELECT b1 = true FROM tb;
+SELECT b1 != true FROM tb;
+
+SELECT true > b1 FROM tb;
+SELECT true < b1 FROM tb;
+SELECT true >= b1 FROM tb;
+SELECT true <= b1 FROM tb;
+SELECT true = b1 FROM tb;
+SELECT true != b1 FROM tb;
+
+SELECT b1 > b2 FROM tb;
+SELECT b1 < b2 FROM tb;
+SELECT b1 >= b2 FROM tb;
+SELECT b1 <= b2 FROM tb;
+SELECT b1 = b2 FROM tb;
+SELECT b1 != b2 FROM tb;
+
+-- Make sure that comparison between STRING values works.
+SELECT '123' > '456';
+SELECT '123' < '456';
+SELECT '123' >= '456';
+SELECT '123' <= '456';
+SELECT '123' = '456';
+SELECT '123' != '456';
+
+CREATE TABLE ts(s1 STRING PRIMARY KEY, s2 STRING);
+INSERT INTO ts VALUES ('12', '32');
+SELECT s1 > '123' FROM ts;
+SELECT s1 < '123' FROM ts;
+SELECT s1 >= '123' FROM ts;
+SELECT s1 <= '123' FROM ts;
+SELECT s1 = '123' FROM ts;
+SELECT s1 != '123' FROM ts;
+
+SELECT '123' > s1 FROM ts;
+SELECT '123' < s1 FROM ts;
+SELECT '123' >= s1 FROM ts;
+SELECT '123' <= s1 FROM ts;
+SELECT '123' = s1 FROM ts;
+SELECT '123' != s1 FROM ts;
+
+SELECT s1 > s2 FROM ts;
+SELECT s1 < s2 FROM ts;
+SELECT s1 >= s2 FROM ts;
+SELECT s1 <= s2 FROM ts;
+SELECT s1 = s2 FROM ts;
+SELECT s1 != s2 FROM ts;
+
+-- Make sure that comparison between VARBINARY values works.
+SELECT X'3139' > X'3537';
+SELECT X'3139' < X'3537';
+SELECT X'3139' >= X'3537';
+SELECT X'3139' <= X'3537';
+SELECT X'3139' = X'3537';
+SELECT X'3139' != X'3537';
+
+CREATE TABLE tv(v1 VARBINARY PRIMARY KEY, v2 VARBINARY);
+INSERT INTO tv VALUES (X'3333', X'3432');
+SELECT v1 > X'3139' FROM tv;
+SELECT v1 < X'3139' FROM tv;
+SELECT v1 >= X'3139' FROM tv;
+SELECT v1 <= X'3139' FROM tv;
+SELECT v1 = X'3139' FROM tv;
+SELECT v1 != X'3139' FROM tv;
+
+SELECT X'3139' > v1 FROM tv;
+SELECT X'3139' < v1 FROM tv;
+SELECT X'3139' >= v1 FROM tv;
+SELECT X'3139' <= v1 FROM tv;
+SELECT X'3139' = v1 FROM tv;
+SELECT X'3139' != v1 FROM tv;
+
+SELECT v1 > v2 FROM tv;
+SELECT v1 < v2 FROM tv;
+SELECT v1 >= v2 FROM tv;
+SELECT v1 <= v2 FROM tv;
+SELECT v1 = v2 FROM tv;
+SELECT v1 != v2 FROM tv;
+
+-- Make sure, that comparison with NULL returns NULL.
+SELECT NULL > NULL, NULL > 1, NULL > 1.5, NULL > true, NULL > '123', NULL > X'3139';
+SELECT NULL < NULL, NULL < 1, NULL < 1.5, NULL < true, NULL < '123', NULL < X'3139';
+SELECT NULL >= NULL, NULL >= 1, NULL >= 1.5, NULL >= true, NULL >= '123', NULL >= X'3139';
+SELECT NULL <= NULL, NULL <= 1, NULL <= 1.5, NULL <= true, NULL <= '123', NULL <= X'3139';
+SELECT NULL = NULL, NULL = 1, NULL = 1.5, NULL = true, NULL = '123', NULL = X'3139';
+SELECT NULL != NULL, NULL != 1, NULL != 1.5, NULL != true, NULL != '123', NULL != X'3139';
+
+SELECT 1 > NULL, 1.5 > NULL, true > NULL, '123' > NULL, X'3139' > NULL;
+SELECT 1 < NULL, 1.5 < NULL, true < NULL, '123' < NULL, X'3139' < NULL;
+SELECT 1 >= NULL, 1.5 >= NULL, true >= NULL, '123' >= NULL, X'3139' >= NULL;
+SELECT 1 <= NULL, 1.5 <= NULL, true <= NULL, '123' <= NULL, X'3139' <= NULL;
+SELECT 1 = NULL, 1.5 = NULL, true = NULL, '123' = NULL, X'3139' = NULL;
+SELECT 1 != NULL, 1.5 != NULL, true != NULL, '123' != NULL, X'3139' != NULL;
+
+SELECT NULL > i, NULL > a, NULL > d, NULL > u, NULL > b1, NULL > s1, NULL > v1 FROM tn, tb, ts, tv;
+SELECT NULL < i, NULL < a, NULL < d, NULL < u, NULL < b1, NULL < s1, NULL < v1 FROM tn, tb, ts, tv;
+SELECT NULL >= i, NULL >= a, NULL >= d, NULL >= u, NULL >= b1, NULL >= s1, NULL >= v1 FROM tn, tb, ts, tv;
+SELECT NULL <= i, NULL <= a, NULL <= d, NULL <= u, NULL <= b1, NULL <= s1, NULL <= v1 FROM tn, tb, ts, tv;
+SELECT NULL = i, NULL = a, NULL = d, NULL = u, NULL = b1, NULL = s1, NULL = v1 FROM tn, tb, ts, tv;
+SELECT NULL != i, NULL != a, NULL != d, NULL != u, NULL != b1, NULL != s1, NULL != v1 FROM tn, tb, ts, tv;
+
+CREATE TABLE t0(pk INT PRIMARY KEY, i0 INT, a0 NUMBER, d0 DOUBLE, u0 UNSIGNED, b0 BOOLEAN, s0 STRING, v0 VARBINARY, sc0 SCALAR);
+INSERT INTO t0 VALUES (1, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+SELECT i0 > i, i0 > a, i0 > d, i0 > u, i0 > b1, i0 > s1, i0 > v1 FROM t0, tn, tb, ts, tv;
+SELECT i0 < i, i0 < a, i0 < d, i0 < u, i0 < b1, i0 < s1, i0 < v1 FROM t0, tn, tb, ts, tv;
+SELECT i0 >= i, i0 >= a, i0 >= d, i0 >= u, i0 >= b1, i0 >= s1, i0 >= v1 FROM t0, tn, tb, ts, tv;
+SELECT i0 <= i, i0 <= a, i0 <= d, i0 <= u, i0 <= b1, i0 <= s1, i0 <= v1 FROM t0, tn, tb, ts, tv;
+SELECT i0 = i, i0 = a, i0 = d, i0 = u, i0 = b1, i0 = s1, i0 = v1 FROM t0, tn, tb, ts, tv;
+SELECT i0 != i, i0 != a, i0 != d, i0 != u, i0 != b1, i0 != s1, i0 != v1 FROM t0, tn, tb, ts, tv;
+
+SELECT i > i0, a > i0, d > i0, u > i0, b1 > i0, s1 > i0, v1 > i0 FROM t0, tn, tb, ts, tv;
+SELECT i < i0, a < i0, d < i0, u < i0, b1 < i0, s1 < i0, v1 < i0 FROM t0, tn, tb, ts, tv;
+SELECT i >= i0, a >= i0, d >= i0, u >= i0, b1 >= i0, s1 >= i0, v1 >= i0 FROM t0, tn, tb, ts, tv;
+SELECT i <= i0, a <= i0, d <= i0, u <= i0, b1 <= i0, s1 <= i0, v1 <= i0 FROM t0, tn, tb, ts, tv;
+SELECT i = i0, a = i0, d = i0, u = i0, b1 = i0, s1 = i0, v1 = i0 FROM t0, tn, tb, ts, tv;
+SELECT i != i0, a != i0, d != i0, u != i0, b1 != i0, s1 != i0, v1 != i0 FROM t0, tn, tb, ts, tv;
+
+SELECT a0 > i, a0 > a, a0 > d, a0 > u, a0 > b1, a0 > s1, a0 > v1 FROM t0, tn, tb, ts, tv;
+SELECT a0 < i, a0 < a, a0 < d, a0 < u, a0 < b1, a0 < s1, a0 < v1 FROM t0, tn, tb, ts, tv;
+SELECT a0 >= i, a0 >= a, a0 >= d, a0 >= u, a0 >= b1, a0 >= s1, a0 >= v1 FROM t0, tn, tb, ts, tv;
+SELECT a0 <= i, a0 <= a, a0 <= d, a0 <= u, a0 <= b1, a0 <= s1, a0 <= v1 FROM t0, tn, tb, ts, tv;
+SELECT a0 = i, a0 = a, a0 = d, a0 = u, a0 = b1, a0 = s1, a0 = v1 FROM t0, tn, tb, ts, tv;
+SELECT a0 != i, a0 != a, a0 != d, a0 != u, a0 != b1, a0 != s1, a0 != v1 FROM t0, tn, tb, ts, tv;
+
+SELECT i > a0, a > a0, d > a0, u > a0, b1 > a0, s1 > a0, v1 > a0 FROM t0, tn, tb, ts, tv;
+SELECT i < a0, a < a0, d < a0, u < a0, b1 < a0, s1 < a0, v1 < a0 FROM t0, tn, tb, ts, tv;
+SELECT i >= a0, a >= a0, d >= a0, u >= a0, b1 >= a0, s1 >= a0, v1 >= a0 FROM t0, tn, tb, ts, tv;
+SELECT i <= a0, a <= a0, d <= a0, u <= a0, b1 <= a0, s1 <= a0, v1 <= a0 FROM t0, tn, tb, ts, tv;
+SELECT i = a0, a = a0, d = a0, u = a0, b1 = a0, s1 = a0, v1 = a0 FROM t0, tn, tb, ts, tv;
+SELECT i != a0, a != a0, d != a0, u != a0, b1 != a0, s1 != a0, v1 != a0 FROM t0, tn, tb, ts, tv;
+
+SELECT d0 > i, d0 > a, d0 > d, d0 > u, d0 > b1, d0 > s1, d0 > v1 FROM t0, tn, tb, ts, tv;
+SELECT d0 < i, d0 < a, d0 < d, d0 < u, d0 < b1, d0 < s1, d0 < v1 FROM t0, tn, tb, ts, tv;
+SELECT d0 >= i, d0 >= a, d0 >= d, d0 >= u, d0 >= b1, d0 >= s1, d0 >= v1 FROM t0, tn, tb, ts, tv;
+SELECT d0 <= i, d0 <= a, d0 <= d, d0 <= u, d0 <= b1, d0 <= s1, d0 <= v1 FROM t0, tn, tb, ts, tv;
+SELECT d0 = i, d0 = a, d0 = d, d0 = u, d0 = b1, d0 = s1, d0 = v1 FROM t0, tn, tb, ts, tv;
+SELECT d0 != i, d0 != a, d0 != d, d0 != u, d0 != b1, d0 != s1, d0 != v1 FROM t0, tn, tb, ts, tv;
+
+SELECT i > d0, a > d0, d > d0, u > d0, b1 > d0, s1 > d0, v1 > d0 FROM t0, tn, tb, ts, tv;
+SELECT i < d0, a < d0, d < d0, u < d0, b1 < d0, s1 < d0, v1 < d0 FROM t0, tn, tb, ts, tv;
+SELECT i >= d0, a >= d0, d >= d0, u >= d0, b1 >= d0, s1 >= d0, v1 >= d0 FROM t0, tn, tb, ts, tv;
+SELECT i <= d0, a <= d0, d <= d0, u <= d0, b1 <= d0, s1 <= d0, v1 <= d0 FROM t0, tn, tb, ts, tv;
+SELECT i = d0, a = d0, d = d0, u = d0, b1 = d0, s1 = d0, v1 = d0 FROM t0, tn, tb, ts, tv;
+SELECT i != d0, a != d0, d != d0, u != d0, b1 != d0, s1 != d0, v1 != d0 FROM t0, tn, tb, ts, tv;
+
+SELECT u0 > i, u0 > a, u0 > d, u0 > u, u0 > b1, u0 > s1, u0 > v1 FROM t0, tn, tb, ts, tv;
+SELECT u0 < i, u0 < a, u0 < d, u0 < u, u0 < b1, u0 < s1, u0 < v1 FROM t0, tn, tb, ts, tv;
+SELECT u0 >= i, u0 >= a, u0 >= d, u0 >= u, u0 >= b1, u0 >= s1, u0 >= v1 FROM t0, tn, tb, ts, tv;
+SELECT u0 <= i, u0 <= a, u0 <= d, u0 <= u, u0 <= b1, u0 <= s1, u0 <= v1 FROM t0, tn, tb, ts, tv;
+SELECT u0 = i, u0 = a, u0 = d, u0 = u, u0 = b1, u0 = s1, u0 = v1 FROM t0, tn, tb, ts, tv;
+SELECT u0 != i, u0 != a, u0 != d, u0 != u, u0 != b1, u0 != s1, u0 != v1 FROM t0, tn, tb, ts, tv;
+
+SELECT i > u0, a > u0, d > u0, u > u0, b1 > u0, s1 > u0, v1 > u0 FROM t0, tn, tb, ts, tv;
+SELECT i < u0, a < u0, d < u0, u < u0, b1 < u0, s1 < u0, v1 < u0 FROM t0, tn, tb, ts, tv;
+SELECT i >= u0, a >= u0, d >= u0, u >= u0, b1 >= u0, s1 >= u0, v1 >= u0 FROM t0, tn, tb, ts, tv;
+SELECT i <= u0, a <= u0, d <= u0, u <= u0, b1 <= u0, s1 <= u0, v1 <= u0 FROM t0, tn, tb, ts, tv;
+SELECT i = u0, a = u0, d = u0, u = u0, b1 = u0, s1 = u0, v1 = u0 FROM t0, tn, tb, ts, tv;
+SELECT i != u0, a != u0, d != u0, u != u0, b1 != u0, s1 != u0, v1 != u0 FROM t0, tn, tb, ts, tv;
+
+SELECT b0 > i, b0 > a, b0 > d, b0 > u, b0 > b1, b0 > s1, b0 > v1 FROM t0, tn, tb, ts, tv;
+SELECT b0 < i, b0 < a, b0 < d, b0 < u, b0 < b1, b0 < s1, b0 < v1 FROM t0, tn, tb, ts, tv;
+SELECT b0 >= i, b0 >= a, b0 >= d, b0 >= u, b0 >= b1, b0 >= s1, b0 >= v1 FROM t0, tn, tb, ts, tv;
+SELECT b0 <= i, b0 <= a, b0 <= d, b0 <= u, b0 <= b1, b0 <= s1, b0 <= v1 FROM t0, tn, tb, ts, tv;
+SELECT b0 = i, b0 = a, b0 = d, b0 = u, b0 = b1, b0 = s1, b0 = v1 FROM t0, tn, tb, ts, tv;
+SELECT b0 != i, b0 != a, b0 != d, b0 != u, b0 != b1, b0 != s1, b0 != v1 FROM t0, tn, tb, ts, tv;
+
+SELECT i > b0, a > b0, d > b0, u > b0, b1 > b0, s1 > b0, v1 > b0 FROM t0, tn, tb, ts, tv;
+SELECT i < b0, a < b0, d < b0, u < b0, b1 < b0, s1 < b0, v1 < b0 FROM t0, tn, tb, ts, tv;
+SELECT i >= b0, a >= b0, d >= b0, u >= b0, b1 >= b0, s1 >= b0, v1 >= b0 FROM t0, tn, tb, ts, tv;
+SELECT i <= b0, a <= b0, d <= b0, u <= b0, b1 <= b0, s1 <= b0, v1 <= b0 FROM t0, tn, tb, ts, tv;
+SELECT i = b0, a = b0, d = b0, u = b0, b1 = b0, s1 = b0, v1 = b0 FROM t0, tn, tb, ts, tv;
+SELECT i != b0, a != b0, d != b0, u != b0, b1 != b0, s1 != b0, v1 != b0 FROM t0, tn, tb, ts, tv;
+
+SELECT s0 > i, s0 > a, s0 > d, s0 > u, s0 > b1, s0 > s1, s0 > v1 FROM t0, tn, tb, ts, tv;
+SELECT s0 < i, s0 < a, s0 < d, s0 < u, s0 < b1, s0 < s1, s0 < v1 FROM t0, tn, tb, ts, tv;
+SELECT s0 >= i, s0 >= a, s0 >= d, s0 >= u, s0 >= b1, s0 >= s1, s0 >= v1 FROM t0, tn, tb, ts, tv;
+SELECT s0 <= i, s0 <= a, s0 <= d, s0 <= u, s0 <= b1, s0 <= s1, s0 <= v1 FROM t0, tn, tb, ts, tv;
+SELECT s0 = i, s0 = a, s0 = d, s0 = u, s0 = b1, s0 = s1, s0 = v1 FROM t0, tn, tb, ts, tv;
+SELECT s0 != i, s0 != a, s0 != d, s0 != u, s0 != b1, s0 != s1, s0 != v1 FROM t0, tn, tb, ts, tv;
+
+SELECT i > s0, a > s0, d > s0, u > s0, b1 > s0, s1 > s0, v1 > s0 FROM t0, tn, tb, ts, tv;
+SELECT i < s0, a < s0, d < s0, u < s0, b1 < s0, s1 < s0, v1 < s0 FROM t0, tn, tb, ts, tv;
+SELECT i >= s0, a >= s0, d >= s0, u >= s0, b1 >= s0, s1 >= s0, v1 >= s0 FROM t0, tn, tb, ts, tv;
+SELECT i <= s0, a <= s0, d <= s0, u <= s0, b1 <= s0, s1 <= s0, v1 <= s0 FROM t0, tn, tb, ts, tv;
+SELECT i = s0, a = s0, d = s0, u = s0, b1 = s0, s1 = s0, v1 = s0 FROM t0, tn, tb, ts, tv;
+SELECT i != s0, a != s0, d != s0, u != s0, b1 != s0, s1 != s0, v1 != s0 FROM t0, tn, tb, ts, tv;
+
+SELECT v0 > i, v0 > a, v0 > d, v0 > u, v0 > b1, v0 > s1, v0 > v1 FROM t0, tn, tb, ts, tv;
+SELECT v0 < i, v0 < a, v0 < d, v0 < u, v0 < b1, v0 < s1, v0 < v1 FROM t0, tn, tb, ts, tv;
+SELECT v0 >= i, v0 >= a, v0 >= d, v0 >= u, v0 >= b1, v0 >= s1, v0 >= v1 FROM t0, tn, tb, ts, tv;
+SELECT v0 <= i, v0 <= a, v0 <= d, v0 <= u, v0 <= b1, v0 <= s1, v0 <= v1 FROM t0, tn, tb, ts, tv;
+SELECT v0 = i, v0 = a, v0 = d, v0 = u, v0 = b1, v0 = s1, v0 = v1 FROM t0, tn, tb, ts, tv;
+SELECT v0 != i, v0 != a, v0 != d, v0 != u, v0 != b1, v0 != s1, v0 != v1 FROM t0, tn, tb, ts, tv;
+
+SELECT i > v0, a > v0, d > v0, u > v0, b1 > v0, s1 > v0, v1 > v0 FROM t0, tn, tb, ts, tv;
+SELECT i < v0, a < v0, d < v0, u < v0, b1 < v0, s1 < v0, v1 < v0 FROM t0, tn, tb, ts, tv;
+SELECT i >= v0, a >= v0, d >= v0, u >= v0, b1 >= v0, s1 >= v0, v1 >= v0 FROM t0, tn, tb, ts, tv;
+SELECT i <= v0, a <= v0, d <= v0, u <= v0, b1 <= v0, s1 <= v0, v1 <= v0 FROM t0, tn, tb, ts, tv;
+SELECT i = v0, a = v0, d = v0, u = v0, b1 = v0, s1 = v0, v1 = v0 FROM t0, tn, tb, ts, tv;
+SELECT i != v0, a != v0, d != v0, u != v0, b1 != v0, s1 != v0, v1 != v0 FROM t0, tn, tb, ts, tv;
+
+SELECT sc0 > i, sc0 > a, sc0 > d, sc0 > u, sc0 > b1, sc0 > s1, sc0 > v1 FROM t0, tn, tb, ts, tv;
+SELECT sc0 < i, sc0 < a, sc0 < d, sc0 < u, sc0 < b1, sc0 < s1, sc0 < v1 FROM t0, tn, tb, ts, tv;
+SELECT sc0 >= i, sc0 >= a, sc0 >= d, sc0 >= u, sc0 >= b1, sc0 >= s1, sc0 >= v1 FROM t0, tn, tb, ts, tv;
+SELECT sc0 <= i, sc0 <= a, sc0 <= d, sc0 <= u, sc0 <= b1, sc0 <= s1, sc0 <= v1 FROM t0, tn, tb, ts, tv;
+SELECT sc0 = i, sc0 = a, sc0 = d, sc0 = u, sc0 = b1, sc0 = s1, sc0 = v1 FROM t0, tn, tb, ts, tv;
+SELECT sc0 != i, sc0 != a, sc0 != d, sc0 != u, sc0 != b1, sc0 != s1, sc0 != v1 FROM t0, tn, tb, ts, tv;
+
+SELECT i > sc0, a > sc0, d > sc0, u > sc0, b1 > sc0, s1 > sc0, v1 > sc0 FROM t0, tn, tb, ts, tv;
+SELECT i < sc0, a < sc0, d < sc0, u < sc0, b1 < sc0, s1 < sc0, v1 < sc0 FROM t0, tn, tb, ts, tv;
+SELECT i >= sc0, a >= sc0, d >= sc0, u >= sc0, b1 >= sc0, s1 >= sc0, v1 >= sc0 FROM t0, tn, tb, ts, tv;
+SELECT i <= sc0, a <= sc0, d <= sc0, u <= sc0, b1 <= sc0, s1 <= sc0, v1 <= sc0 FROM t0, tn, tb, ts, tv;
+SELECT i = sc0, a = sc0, d = sc0, u = sc0, b1 = sc0, s1 = sc0, v1 = sc0 FROM t0, tn, tb, ts, tv;
+SELECT i != sc0, a != sc0, d != sc0, u != sc0, b1 != sc0, s1 != sc0, v1 != sc0 FROM t0, tn, tb, ts, tv;
+
+-- Make sure that numbers cannot be compared with BOOLEAN values.
+SELECT 3 > true;
+SELECT 3 < true;
+SELECT 3 >= true;
+SELECT 3 <= true;
+SELECT 3 = true;
+SELECT 3 != true;
+
+SELECT true > 4;
+SELECT true < 4;
+SELECT true >= 4;
+SELECT true <= 4;
+SELECT true = 4;
+SELECT true != 4;
+
+SELECT 3.5 > true;
+SELECT 3.5 < true;
+SELECT 3.5 >= true;
+SELECT 3.5 <= true;
+SELECT 3.5 = true;
+SELECT 3.5 != true;
+
+SELECT true > 0.5;
+SELECT true < 0.5;
+SELECT true >= 0.5;
+SELECT true <= 0.5;
+SELECT true = 0.5;
+SELECT true != 0.5;
+
+SELECT i > true FROM tn;
+SELECT i < true FROM tn;
+SELECT i >= true FROM tn;
+SELECT i <= true FROM tn;
+SELECT i = true FROM tn;
+SELECT i != true FROM tn;
+
+SELECT true > i FROM tn;
+SELECT true < i FROM tn;
+SELECT true >= i FROM tn;
+SELECT true <= i FROM tn;
+SELECT true = i FROM tn;
+SELECT true != i FROM tn;
+
+SELECT a > true FROM tn;
+SELECT a < true FROM tn;
+SELECT a >= true FROM tn;
+SELECT a <= true FROM tn;
+SELECT a = true FROM tn;
+SELECT a != true FROM tn;
+
+SELECT true > a FROM tn;
+SELECT true < a FROM tn;
+SELECT true >= a FROM tn;
+SELECT true <= a FROM tn;
+SELECT true = a FROM tn;
+SELECT true != a FROM tn;
+
+SELECT d > true FROM tn;
+SELECT d < true FROM tn;
+SELECT d >= true FROM tn;
+SELECT d <= true FROM tn;
+SELECT d = true FROM tn;
+SELECT d != true FROM tn;
+
+SELECT true > d FROM tn;
+SELECT true < d FROM tn;
+SELECT true >= d FROM tn;
+SELECT true <= d FROM tn;
+SELECT true = d FROM tn;
+SELECT true != d FROM tn;
+
+SELECT u > true FROM tn;
+SELECT u < true FROM tn;
+SELECT u >= true FROM tn;
+SELECT u <= true FROM tn;
+SELECT u = true FROM tn;
+SELECT u != true FROM tn;
+
+SELECT true > u FROM tn;
+SELECT true < u FROM tn;
+SELECT true >= u FROM tn;
+SELECT true <= u FROM tn;
+SELECT true = u FROM tn;
+SELECT true != u FROM tn;
+
+SELECT 3 > b1 FROM tb;
+SELECT 3 < b1 FROM tb;
+SELECT 3 >= b1 FROM tb;
+SELECT 3 <= b1 FROM tb;
+SELECT 3 = b1 FROM tb;
+SELECT 3 != b1 FROM tb;
+
+SELECT b1 > 4 FROM tb;
+SELECT b1 < 4 FROM tb;
+SELECT b1 >= 4 FROM tb;
+SELECT b1 <= 4 FROM tb;
+SELECT b1 = 4 FROM tb;
+SELECT b1 != 4 FROM tb;
+
+SELECT 3.5 > b1 FROM tb;
+SELECT 3.5 < b1 FROM tb;
+SELECT 3.5 >= b1 FROM tb;
+SELECT 3.5 <= b1 FROM tb;
+SELECT 3.5 = b1 FROM tb;
+SELECT 3.5 != b1 FROM tb;
+
+SELECT b1 > 0.5 FROM tb;
+SELECT b1 < 0.5 FROM tb;
+SELECT b1 >= 0.5 FROM tb;
+SELECT b1 <= 0.5 FROM tb;
+SELECT b1 = 0.5 FROM tb;
+SELECT b1 != 0.5 FROM tb;
+
+SELECT i > b1 FROM tn, tb;
+SELECT i < b1 FROM tn, tb;
+SELECT i >= b1 FROM tn, tb;
+SELECT i <= b1 FROM tn, tb;
+SELECT i = b1 FROM tn, tb;
+SELECT i != b1 FROM tn, tb;
+
+SELECT b1 > i FROM tn, tb;
+SELECT b1 < i FROM tn, tb;
+SELECT b1 >= i FROM tn, tb;
+SELECT b1 <= i FROM tn, tb;
+SELECT b1 = i FROM tn, tb;
+SELECT b1 != i FROM tn, tb;
+
+SELECT a > b1 FROM tn, tb;
+SELECT a < b1 FROM tn, tb;
+SELECT a >= b1 FROM tn, tb;
+SELECT a <= b1 FROM tn, tb;
+SELECT a = b1 FROM tn, tb;
+SELECT a != b1 FROM tn, tb;
+
+SELECT b1 > a FROM tn, tb;
+SELECT b1 < a FROM tn, tb;
+SELECT b1 >= a FROM tn, tb;
+SELECT b1 <= a FROM tn, tb;
+SELECT b1 = a FROM tn, tb;
+SELECT b1 != a FROM tn, tb;
+
+SELECT d > b1 FROM tn, tb;
+SELECT d < b1 FROM tn, tb;
+SELECT d >= b1 FROM tn, tb;
+SELECT d <= b1 FROM tn, tb;
+SELECT d = b1 FROM tn, tb;
+SELECT d != b1 FROM tn, tb;
+
+SELECT b1 > d FROM tn, tb;
+SELECT b1 < d FROM tn, tb;
+SELECT b1 >= d FROM tn, tb;
+SELECT b1 <= d FROM tn, tb;
+SELECT b1 = d FROM tn, tb;
+SELECT b1 != d FROM tn, tb;
+
+SELECT u > b1 FROM tn, tb;
+SELECT u < b1 FROM tn, tb;
+SELECT u >= b1 FROM tn, tb;
+SELECT u <= b1 FROM tn, tb;
+SELECT u = b1 FROM tn, tb;
+SELECT u != b1 FROM tn, tb;
+
+SELECT b1 > u FROM tn, tb;
+SELECT b1 < u FROM tn, tb;
+SELECT b1 >= u FROM tn, tb;
+SELECT b1 <= u FROM tn, tb;
+SELECT b1 = u FROM tn, tb;
+SELECT b1 != u FROM tn, tb;
+
+-- Make sure that numbers cannot be compared with STRING values.
+SELECT 3 > '123';
+SELECT 3 < '123';
+SELECT 3 >= '123';
+SELECT 3 <= '123';
+SELECT 3 = '123';
+SELECT 3 != '123';
+
+SELECT '123' > 4;
+SELECT '123' < 4;
+SELECT '123' >= 4;
+SELECT '123' <= 4;
+SELECT '123' = 4;
+SELECT '123' != 4;
+
+SELECT 3.5 > '123';
+SELECT 3.5 < '123';
+SELECT 3.5 >= '123';
+SELECT 3.5 <= '123';
+SELECT 3.5 = '123';
+SELECT 3.5 != '123';
+
+SELECT '123' > 0.5;
+SELECT '123' < 0.5;
+SELECT '123' >= 0.5;
+SELECT '123' <= 0.5;
+SELECT '123' = 0.5;
+SELECT '123' != 0.5;
+
+SELECT i > '123' FROM tn;
+SELECT i < '123' FROM tn;
+SELECT i >= '123' FROM tn;
+SELECT i <= '123' FROM tn;
+SELECT i = '123' FROM tn;
+SELECT i != '123' FROM tn;
+
+SELECT '123' > i FROM tn;
+SELECT '123' < i FROM tn;
+SELECT '123' >= i FROM tn;
+SELECT '123' <= i FROM tn;
+SELECT '123' = i FROM tn;
+SELECT '123' != i FROM tn;
+
+SELECT a > '123' FROM tn;
+SELECT a < '123' FROM tn;
+SELECT a >= '123' FROM tn;
+SELECT a <= '123' FROM tn;
+SELECT a = '123' FROM tn;
+SELECT a != '123' FROM tn;
+
+SELECT '123' > a FROM tn;
+SELECT '123' < a FROM tn;
+SELECT '123' >= a FROM tn;
+SELECT '123' <= a FROM tn;
+SELECT '123' = a FROM tn;
+SELECT '123' != a FROM tn;
+
+SELECT d > '123' FROM tn;
+SELECT d < '123' FROM tn;
+SELECT d >= '123' FROM tn;
+SELECT d <= '123' FROM tn;
+SELECT d = '123' FROM tn;
+SELECT d != '123' FROM tn;
+
+SELECT '123' > d FROM tn;
+SELECT '123' < d FROM tn;
+SELECT '123' >= d FROM tn;
+SELECT '123' <= d FROM tn;
+SELECT '123' = d FROM tn;
+SELECT '123' != d FROM tn;
+
+SELECT u > '123' FROM tn;
+SELECT u < '123' FROM tn;
+SELECT u >= '123' FROM tn;
+SELECT u <= '123' FROM tn;
+SELECT u = '123' FROM tn;
+SELECT u != '123' FROM tn;
+
+SELECT '123' > u FROM tn;
+SELECT '123' < u FROM tn;
+SELECT '123' >= u FROM tn;
+SELECT '123' <= u FROM tn;
+SELECT '123' = u FROM tn;
+SELECT '123' != u FROM tn;
+
+SELECT 3 > s1 FROM ts;
+SELECT 3 < s1 FROM ts;
+SELECT 3 >= s1 FROM ts;
+SELECT 3 <= s1 FROM ts;
+SELECT 3 = s1 FROM ts;
+SELECT 3 != s1 FROM ts;
+
+SELECT s1 > 4 FROM ts;
+SELECT s1 < 4 FROM ts;
+SELECT s1 >= 4 FROM ts;
+SELECT s1 <= 4 FROM ts;
+SELECT s1 = 4 FROM ts;
+SELECT s1 != 4 FROM ts;
+
+SELECT 3.5 > s1 FROM ts;
+SELECT 3.5 < s1 FROM ts;
+SELECT 3.5 >= s1 FROM ts;
+SELECT 3.5 <= s1 FROM ts;
+SELECT 3.5 = s1 FROM ts;
+SELECT 3.5 != s1 FROM ts;
+
+SELECT s1 > 0.5 FROM ts;
+SELECT s1 < 0.5 FROM ts;
+SELECT s1 >= 0.5 FROM ts;
+SELECT s1 <= 0.5 FROM ts;
+SELECT s1 = 0.5 FROM ts;
+SELECT s1 != 0.5 FROM ts;
+
+SELECT i > s1 FROM tn, ts;
+SELECT i < s1 FROM tn, ts;
+SELECT i >= s1 FROM tn, ts;
+SELECT i <= s1 FROM tn, ts;
+SELECT i = s1 FROM tn, ts;
+SELECT i != s1 FROM tn, ts;
+
+SELECT s1 > i FROM tn, ts;
+SELECT s1 < i FROM tn, ts;
+SELECT s1 >= i FROM tn, ts;
+SELECT s1 <= i FROM tn, ts;
+SELECT s1 = i FROM tn, ts;
+SELECT s1 != i FROM tn, ts;
+
+SELECT a > s1 FROM tn, ts;
+SELECT a < s1 FROM tn, ts;
+SELECT a >= s1 FROM tn, ts;
+SELECT a <= s1 FROM tn, ts;
+SELECT a = s1 FROM tn, ts;
+SELECT a != s1 FROM tn, ts;
+
+SELECT s1 > a FROM tn, ts;
+SELECT s1 < a FROM tn, ts;
+SELECT s1 >= a FROM tn, ts;
+SELECT s1 <= a FROM tn, ts;
+SELECT s1 = a FROM tn, ts;
+SELECT s1 != a FROM tn, ts;
+
+SELECT d > s1 FROM tn, ts;
+SELECT d < s1 FROM tn, ts;
+SELECT d >= s1 FROM tn, ts;
+SELECT d <= s1 FROM tn, ts;
+SELECT d = s1 FROM tn, ts;
+SELECT d != s1 FROM tn, ts;
+
+SELECT s1 > d FROM tn, ts;
+SELECT s1 < d FROM tn, ts;
+SELECT s1 >= d FROM tn, ts;
+SELECT s1 <= d FROM tn, ts;
+SELECT s1 = d FROM tn, ts;
+SELECT s1 != d FROM tn, ts;
+
+SELECT u > s1 FROM tn, ts;
+SELECT u < s1 FROM tn, ts;
+SELECT u >= s1 FROM tn, ts;
+SELECT u <= s1 FROM tn, ts;
+SELECT u = s1 FROM tn, ts;
+SELECT u != s1 FROM tn, ts;
+
+SELECT s1 > u FROM tn, ts;
+SELECT s1 < u FROM tn, ts;
+SELECT s1 >= u FROM tn, ts;
+SELECT s1 <= u FROM tn, ts;
+SELECT s1 = u FROM tn, ts;
+SELECT s1 != u FROM tn, ts;
+
+--
+-- Make sure that numbers cannot be compared with VARBINARY
+-- values.
+--
+SELECT 3 > X'3139';
+SELECT 3 < X'3139';
+SELECT 3 >= X'3139';
+SELECT 3 <= X'3139';
+SELECT 3 = X'3139';
+SELECT 3 != X'3139';
+
+SELECT X'3139' > 4;
+SELECT X'3139' < 4;
+SELECT X'3139' >= 4;
+SELECT X'3139' <= 4;
+SELECT X'3139' = 4;
+SELECT X'3139' != 4;
+
+SELECT 3.5 > X'3139';
+SELECT 3.5 < X'3139';
+SELECT 3.5 >= X'3139';
+SELECT 3.5 <= X'3139';
+SELECT 3.5 = X'3139';
+SELECT 3.5 != X'3139';
+
+SELECT X'3139' > 0.5;
+SELECT X'3139' < 0.5;
+SELECT X'3139' >= 0.5;
+SELECT X'3139' <= 0.5;
+SELECT X'3139' = 0.5;
+SELECT X'3139' != 0.5;
+
+SELECT i > X'3139' FROM tn;
+SELECT i < X'3139' FROM tn;
+SELECT i >= X'3139' FROM tn;
+SELECT i <= X'3139' FROM tn;
+SELECT i = X'3139' FROM tn;
+SELECT i != X'3139' FROM tn;
+
+SELECT X'3139' > i FROM tn;
+SELECT X'3139' < i FROM tn;
+SELECT X'3139' >= i FROM tn;
+SELECT X'3139' <= i FROM tn;
+SELECT X'3139' = i FROM tn;
+SELECT X'3139' != i FROM tn;
+
+SELECT a > X'3139' FROM tn;
+SELECT a < X'3139' FROM tn;
+SELECT a >= X'3139' FROM tn;
+SELECT a <= X'3139' FROM tn;
+SELECT a = X'3139' FROM tn;
+SELECT a != X'3139' FROM tn;
+
+SELECT X'3139' > a FROM tn;
+SELECT X'3139' < a FROM tn;
+SELECT X'3139' >= a FROM tn;
+SELECT X'3139' <= a FROM tn;
+SELECT X'3139' = a FROM tn;
+SELECT X'3139' != a FROM tn;
+
+SELECT d > X'3139' FROM tn;
+SELECT d < X'3139' FROM tn;
+SELECT d >= X'3139' FROM tn;
+SELECT d <= X'3139' FROM tn;
+SELECT d = X'3139' FROM tn;
+SELECT d != X'3139' FROM tn;
+
+SELECT X'3139' > d FROM tn;
+SELECT X'3139' < d FROM tn;
+SELECT X'3139' >= d FROM tn;
+SELECT X'3139' <= d FROM tn;
+SELECT X'3139' = d FROM tn;
+SELECT X'3139' != d FROM tn;
+
+SELECT u > X'3139' FROM tn;
+SELECT u < X'3139' FROM tn;
+SELECT u >= X'3139' FROM tn;
+SELECT u <= X'3139' FROM tn;
+SELECT u = X'3139' FROM tn;
+SELECT u != X'3139' FROM tn;
+
+SELECT X'3139' > u FROM tn;
+SELECT X'3139' < u FROM tn;
+SELECT X'3139' >= u FROM tn;
+SELECT X'3139' <= u FROM tn;
+SELECT X'3139' = u FROM tn;
+SELECT X'3139' != u FROM tn;
+
+SELECT 3 > v1 FROM tv;
+SELECT 3 < v1 FROM tv;
+SELECT 3 >= v1 FROM tv;
+SELECT 3 <= v1 FROM tv;
+SELECT 3 = v1 FROM tv;
+SELECT 3 != v1 FROM tv;
+
+SELECT v1 > 4 FROM tv;
+SELECT v1 < 4 FROM tv;
+SELECT v1 >= 4 FROM tv;
+SELECT v1 <= 4 FROM tv;
+SELECT v1 = 4 FROM tv;
+SELECT v1 != 4 FROM tv;
+
+SELECT 3.5 > v1 FROM tv;
+SELECT 3.5 < v1 FROM tv;
+SELECT 3.5 >= v1 FROM tv;
+SELECT 3.5 <= v1 FROM tv;
+SELECT 3.5 = v1 FROM tv;
+SELECT 3.5 != v1 FROM tv;
+
+SELECT v1 > 0.5 FROM tv;
+SELECT v1 < 0.5 FROM tv;
+SELECT v1 >= 0.5 FROM tv;
+SELECT v1 <= 0.5 FROM tv;
+SELECT v1 = 0.5 FROM tv;
+SELECT v1 != 0.5 FROM tv;
+
+SELECT i > v1 FROM tn, tv;
+SELECT i < v1 FROM tn, tv;
+SELECT i >= v1 FROM tn, tv;
+SELECT i <= v1 FROM tn, tv;
+SELECT i = v1 FROM tn, tv;
+SELECT i != v1 FROM tn, tv;
+
+SELECT v1 > i FROM tn, tv;
+SELECT v1 < i FROM tn, tv;
+SELECT v1 >= i FROM tn, tv;
+SELECT v1 <= i FROM tn, tv;
+SELECT v1 = i FROM tn, tv;
+SELECT v1 != i FROM tn, tv;
+
+SELECT a > v1 FROM tn, tv;
+SELECT a < v1 FROM tn, tv;
+SELECT a >= v1 FROM tn, tv;
+SELECT a <= v1 FROM tn, tv;
+SELECT a = v1 FROM tn, tv;
+SELECT a != v1 FROM tn, tv;
+
+SELECT v1 > a FROM tn, tv;
+SELECT v1 < a FROM tn, tv;
+SELECT v1 >= a FROM tn, tv;
+SELECT v1 <= a FROM tn, tv;
+SELECT v1 = a FROM tn, tv;
+SELECT v1 != a FROM tn, tv;
+
+SELECT d > v1 FROM tn, tv;
+SELECT d < v1 FROM tn, tv;
+SELECT d >= v1 FROM tn, tv;
+SELECT d <= v1 FROM tn, tv;
+SELECT d = v1 FROM tn, tv;
+SELECT d != v1 FROM tn, tv;
+
+SELECT v1 > d FROM tn, tv;
+SELECT v1 < d FROM tn, tv;
+SELECT v1 >= d FROM tn, tv;
+SELECT v1 <= d FROM tn, tv;
+SELECT v1 = d FROM tn, tv;
+SELECT v1 != d FROM tn, tv;
+
+SELECT u > v1 FROM tn, tv;
+SELECT u < v1 FROM tn, tv;
+SELECT u >= v1 FROM tn, tv;
+SELECT u <= v1 FROM tn, tv;
+SELECT u = v1 FROM tn, tv;
+SELECT u != v1 FROM tn, tv;
+
+SELECT v1 > u FROM tn, tv;
+SELECT v1 < u FROM tn, tv;
+SELECT v1 >= u FROM tn, tv;
+SELECT v1 <= u FROM tn, tv;
+SELECT v1 = u FROM tn, tv;
+SELECT v1 != u FROM tn, tv;
+
+--
+-- Make sure that BOOLEAN values cannot be compared with STRING
+-- values.
+--
+SELECT true > 'TRUE';
+SELECT true < 'TRUE';
+SELECT true >= 'TRUE';
+SELECT true <= 'TRUE';
+SELECT true = 'TRUE';
+SELECT true != 'TRUE';
+
+SELECT 'TRUE' > true;
+SELECT 'TRUE' < true;
+SELECT 'TRUE' >= true;
+SELECT 'TRUE' <= true;
+SELECT 'TRUE' = true;
+SELECT 'TRUE' != true;
+
+SELECT b1 > 'TRUE' FROM tb;
+SELECT b1 < 'TRUE' FROM tb;
+SELECT b1 >= 'TRUE' FROM tb;
+SELECT b1 <= 'TRUE' FROM tb;
+SELECT b1 = 'TRUE' FROM tb;
+SELECT b1 != 'TRUE' FROM tb;
+
+SELECT 'TRUE' > b1 FROM tb;
+SELECT 'TRUE' < b1 FROM tb;
+SELECT 'TRUE' >= b1 FROM tb;
+SELECT 'TRUE' <= b1 FROM tb;
+SELECT 'TRUE' = b1 FROM tb;
+SELECT 'TRUE' != b1 FROM tb;
+
+SELECT true > s1 FROM ts;
+SELECT true < s1 FROM ts;
+SELECT true >= s1 FROM ts;
+SELECT true <= s1 FROM ts;
+SELECT true = s1 FROM ts;
+SELECT true != s1 FROM ts;
+
+SELECT s1 > true FROM ts;
+SELECT s1 < true FROM ts;
+SELECT s1 >= true FROM ts;
+SELECT s1 <= true FROM ts;
+SELECT s1 = true FROM ts;
+SELECT s1 != true FROM ts;
+
+SELECT b1 > s1 FROM tb, ts;
+SELECT b1 < s1 FROM tb, ts;
+SELECT b1 >= s1 FROM tb, ts;
+SELECT b1 <= s1 FROM tb, ts;
+SELECT b1 = s1 FROM tb, ts;
+SELECT b1 != s1 FROM tb, ts;
+
+SELECT s1 > b1 FROM tb, ts;
+SELECT s1 < b1 FROM tb, ts;
+SELECT s1 >= b1 FROM tb, ts;
+SELECT s1 <= b1 FROM tb, ts;
+SELECT s1 = b1 FROM tb, ts;
+SELECT s1 != b1 FROM tb, ts;
+
+--
+-- Make sure that BOOLEAN values cannot be compared with VARBINARY
+-- values.
+--
+SELECT true > X'54525545';
+SELECT true < X'54525545';
+SELECT true >= X'54525545';
+SELECT true <= X'54525545';
+SELECT true = X'54525545';
+SELECT true != X'54525545';
+
+SELECT X'54525545' > true;
+SELECT X'54525545' < true;
+SELECT X'54525545' >= true;
+SELECT X'54525545' <= true;
+SELECT X'54525545' = true;
+SELECT X'54525545' != true;
+
+SELECT b1 > X'54525545' FROM tb;
+SELECT b1 < X'54525545' FROM tb;
+SELECT b1 >= X'54525545' FROM tb;
+SELECT b1 <= X'54525545' FROM tb;
+SELECT b1 = X'54525545' FROM tb;
+SELECT b1 != X'54525545' FROM tb;
+
+SELECT X'54525545' > b1 FROM tb;
+SELECT X'54525545' < b1 FROM tb;
+SELECT X'54525545' >= b1 FROM tb;
+SELECT X'54525545' <= b1 FROM tb;
+SELECT X'54525545' = b1 FROM tb;
+SELECT X'54525545' != b1 FROM tb;
+
+DELETE FROM tv;
+INSERT INTO tv VALUES (X'54525545', X'54525545');
+
+SELECT true > v1 FROM tv;
+SELECT true < v1 FROM tv;
+SELECT true >= v1 FROM tv;
+SELECT true <= v1 FROM tv;
+SELECT true = v1 FROM tv;
+SELECT true != v1 FROM tv;
+
+SELECT v1 > true FROM tv;
+SELECT v1 < true FROM tv;
+SELECT v1 >= true FROM tv;
+SELECT v1 <= true FROM tv;
+SELECT v1 = true FROM tv;
+SELECT v1 != true FROM tv;
+
+SELECT b1 > v1 FROM tb, tv;
+SELECT b1 < v1 FROM tb, tv;
+SELECT b1 >= v1 FROM tb, tv;
+SELECT b1 <= v1 FROM tb, tv;
+SELECT b1 = v1 FROM tb, tv;
+SELECT b1 != v1 FROM tb, tv;
+
+SELECT v1 > b1 FROM tb, tv;
+SELECT v1 < b1 FROM tb, tv;
+SELECT v1 >= b1 FROM tb, tv;
+SELECT v1 <= b1 FROM tb, tv;
+SELECT v1 = b1 FROM tb, tv;
+SELECT v1 != b1 FROM tb, tv;
+
+--
+-- Make sure that STRING values cannot be compared with VARBINARY
+-- values.
+--
+SELECT '123' > X'54525545';
+SELECT '123' < X'54525545';
+SELECT '123' >= X'54525545';
+SELECT '123' <= X'54525545';
+SELECT '123' = X'54525545';
+SELECT '123' != X'54525545';
+
+SELECT X'54525545' > '123';
+SELECT X'54525545' < '123';
+SELECT X'54525545' >= '123';
+SELECT X'54525545' <= '123';
+SELECT X'54525545' = '123';
+SELECT X'54525545' != '123';
+
+SELECT s1 > X'54525545' FROM ts;
+SELECT s1 < X'54525545' FROM ts;
+SELECT s1 >= X'54525545' FROM ts;
+SELECT s1 <= X'54525545' FROM ts;
+SELECT s1 = X'54525545' FROM ts;
+SELECT s1 != X'54525545' FROM ts;
+
+SELECT X'54525545' > s1 FROM ts;
+SELECT X'54525545' < s1 FROM ts;
+SELECT X'54525545' >= s1 FROM ts;
+SELECT X'54525545' <= s1 FROM ts;
+SELECT X'54525545' = s1 FROM ts;
+SELECT X'54525545' != s1 FROM ts;
+
+SELECT '123' > v1 FROM tv;
+SELECT '123' < v1 FROM tv;
+SELECT '123' >= v1 FROM tv;
+SELECT '123' <= v1 FROM tv;
+SELECT '123' = v1 FROM tv;
+SELECT '123' != v1 FROM tv;
+
+SELECT v1 > '123' FROM tv;
+SELECT v1 < '123' FROM tv;
+SELECT v1 >= '123' FROM tv;
+SELECT v1 <= '123' FROM tv;
+SELECT v1 = '123' FROM tv;
+SELECT v1 != '123' FROM tv;
+
+SELECT s1 > v1 FROM ts, tv;
+SELECT s1 < v1 FROM ts, tv;
+SELECT s1 >= v1 FROM ts, tv;
+SELECT s1 <= v1 FROM ts, tv;
+SELECT s1 = v1 FROM ts, tv;
+SELECT s1 != v1 FROM ts, tv;
+
+SELECT v1 > s1 FROM ts, tv;
+SELECT v1 < s1 FROM ts, tv;
+SELECT v1 >= s1 FROM ts, tv;
+SELECT v1 <= s1 FROM ts, tv;
+SELECT v1 = s1 FROM ts, tv;
+SELECT v1 != s1 FROM ts, tv;
diff --git a/test/sql/types.result b/test/sql/types.result
index 38e4385..50c64f5 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -614,10 +614,10 @@ box.execute("SELECT 18446744073709551615.0 > 18446744073709551615")
   rows:
   - [true]
 ...
-box.execute("SELECT 18446744073709551615 IN ('18446744073709551615', 18446744073709551615.0)")
+box.execute("SELECT 18446744073709551615 IN (CAST('18446744073709551615' AS INTEGER), 18446744073709551615.0)")
 ---
 - metadata:
-  - name: 18446744073709551615 IN ('18446744073709551615', 18446744073709551615.0)
+  - name: 18446744073709551615 IN (CAST('18446744073709551615' AS INTEGER), 18446744073709551615.0)
     type: boolean
   rows:
   - [true]
diff --git a/test/sql/types.test.lua b/test/sql/types.test.lua
index bd14b34..497fb34 100644
--- a/test/sql/types.test.lua
+++ b/test/sql/types.test.lua
@@ -151,7 +151,7 @@ box.execute("SELECT 18446744073709551610 - 18446744073709551615;")
 box.execute("SELECT 18446744073709551615 = null;")
 box.execute("SELECT 18446744073709551615 = 18446744073709551615.0;")
 box.execute("SELECT 18446744073709551615.0 > 18446744073709551615")
-box.execute("SELECT 18446744073709551615 IN ('18446744073709551615', 18446744073709551615.0)")
+box.execute("SELECT 18446744073709551615 IN (CAST('18446744073709551615' AS INTEGER), 18446744073709551615.0)")
 box.execute("SELECT 1 LIMIT 18446744073709551615;")
 box.execute("SELECT 1 LIMIT 1 OFFSET 18446744073709551614;")
 box.execute("SELECT CAST('18446744073' || '709551616' AS INTEGER);")
-- 
2.7.4

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2020-04-26 18:22 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-20 12:34 [Tarantool-patches] [PATCH v1 1/1] sql: remove implicit cast for COMPARISON imeevma
2020-03-29 22:29 ` Vladislav Shpilevoy
2020-03-30 11:38   ` Nikita Pettik
2020-03-30 16:53     ` Mergen Imeev
2020-04-02 23:47       ` Vladislav Shpilevoy
2020-04-21 12:42   ` Mergen Imeev
2020-04-26 18:22     ` Vladislav Shpilevoy
  -- strict thread matches above, loose matches on Subject: below --
2020-02-20  8:00 imeevma

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox