Browse Source

Merge pull request #4073 from cakephp/3.0-db-expression-tweaks

Improve query expression operators
Mark Story 11 years ago
parent
commit
61e75f82ce

+ 8 - 0
src/Database/Expression/Comparison.php

@@ -131,10 +131,17 @@ class Comparison extends QueryExpression {
 			$template = '%s %s (%s)';
 			$type = str_replace('[]', '', $this->_type);
 			$value = $this->_flattenValue($this->_value, $generator, $type);
+
+			// To avoid SQL erros when comparing a field to a list of empty values,
+			// generate a condition that will always evaluate to false
+			if ($value === '') {
+				return ['1 != 1', ''];
+			}
 		} else {
 			$template = '%s %s %s';
 			$value = $this->_bindValue($this->_value, $generator, $this->_type);
 		}
+
 		return [$template, $value];
 	}
 
@@ -166,6 +173,7 @@ class Comparison extends QueryExpression {
 		foreach ($value as $k => $v) {
 			$parts[] = $this->_bindValue($v, $generator, $type);
 		}
+
 		return implode(',', $parts);
 	}
 

+ 10 - 1
src/Database/Expression/QueryExpression.php

@@ -488,9 +488,10 @@ class QueryExpression implements ExpressionInterface, Countable {
 
 		$type = $this->typeMap()->type($expression);
 		$multi = false;
+		$operator = strtolower(trim($operator));
 
 		$typeMultiple = strpos($type, '[]') !== false;
-		if (in_array(strtolower(trim($operator)), ['in', 'not in']) || $typeMultiple) {
+		if (in_array($operator, ['in', 'not in']) || $typeMultiple) {
 			$type = $type ?: 'string';
 			$type .= $typeMultiple ? null : '[]';
 			$operator = $operator === '=' ? 'IN' : $operator;
@@ -502,6 +503,14 @@ class QueryExpression implements ExpressionInterface, Countable {
 			$value = $value instanceof ExpressionInterface ? $value : (array)$value;
 		}
 
+		if ($operator === 'is' && $value === null) {
+			return new UnaryExpression('IS NULL', $expression, UnaryExpression::POSTFIX);
+		}
+
+		if ($operator === 'is' && $value !== null) {
+			$operator = '=';
+		}
+
 		return new Comparison($expression, $value, $type, $operator);
 	}
 

+ 39 - 0
tests/TestCase/Database/QueryTest.php

@@ -592,6 +592,22 @@ class QueryTest extends TestCase {
 	}
 
 /**
+ * Tests that passing an empty array type to any where condition will not
+ * result in an error, but in an empty result set
+ *
+ * @return void
+ */
+	public function testSelectWhereArrayTypeEmpty() {
+		$query = new Query($this->connection);
+		$result = $query
+			->select(['id'])
+			->from('comments')
+			->where(['id' => []], ['id' => 'integer[]'])
+			->execute();
+		$this->assertCount(0, $result);
+	}
+
+/**
  * Tests that Query::orWhere() can be used to concatenate conditions with OR
  *
  * @return void
@@ -2678,6 +2694,29 @@ class QueryTest extends TestCase {
 	}
 
 /**
+ * Tests that using the IS operator will automatically translate to the best
+ * possible operator depending on the passed value
+ *
+ * @return void
+ */
+	public function testDirectIsNull() {
+		$sql = (new Query($this->connection))
+			->select(['name'])
+			->from(['authors'])
+			->where(['name IS' => null])
+			->sql();
+		$this->assertQuotedQuery('WHERE \(<name>\) IS NULL', $sql, true);
+
+		$results = (new Query($this->connection))
+			->select(['name'])
+			->from(['authors'])
+			->where(['name IS' => 'larry'])
+			->execute();
+		$this->assertCount(1, $results);
+		$this->assertEquals(['name' => 'larry'], $results->fetch('assoc'));
+	}
+
+/**
  * Assertion for comparing a table's contents with what is in it.
  *
  * @param string $table