4 * Class CRM_Utils_SQL_SelectTest
7 class CRM_Utils_SQL_SelectTest
extends CiviUnitTestCase
{
8 public function testGetDefault() {
9 $select = CRM_Utils_SQL_Select
::from('foo bar');
10 $this->assertLike('SELECT * FROM foo bar', $select->toSQL());
13 public function testExecute_OK() {
14 // We need some SQL query.
15 $select = CRM_Utils_SQL_Select
::from('civicrm_contact')
16 ->select('count(*) as cnt');
17 $this->assertLike('SELECT count(*) as cnt FROM civicrm_contact', $select->toSQL());
19 // Try with typical fetch().
21 $dao = $select->execute();
22 while ($dao->fetch()) {
24 $this->assertTrue(is_numeric($dao->cnt
), "Expect query to execute");
26 $this->assertEquals(1, $rows);
28 // Try with fetchValue().
29 $this->assertTrue(is_numeric($select->execute()->fetchValue()));
31 // Try with fetchAll()
32 $records = $select->execute()->fetchAll();
33 $this->assertTrue(is_numeric($records[0]['cnt']));
36 public function testExecute_Error() {
38 CRM_Utils_SQL_Select
::from('civicrm_contact')->select('snarb;barg')->execute();
39 $this->fail('Expected an exception');
41 catch (PEAR_Exception
$e) {
42 $this->assertTrue(TRUE, "Received expected exception");
46 public function testGetFields() {
47 $select = CRM_Utils_SQL_Select
::from('foo')
49 ->select(array('whiz', 'bang'));
50 $this->assertLike('SELECT bar, whiz, bang FROM foo', $select->toSQL());
53 public function testWherePlain() {
54 $select = CRM_Utils_SQL_Select
::from('foo')
56 ->where(array('whiz = bang', 'frob > nicate'));
57 $this->assertLike('SELECT * FROM foo WHERE (foo = bar) AND (whiz = bang) AND (frob > nicate)', $select->toSQL());
60 public function testWhereArg() {
61 $select = CRM_Utils_SQL_Select
::from('foo')
62 ->where('foo = @value', array('@value' => 'not"valid'))
63 ->where(array('whiz > @base', 'frob != @base'), array('@base' => 'in"valid'));
64 $this->assertLike('SELECT * FROM foo WHERE (foo = "not\\"valid") AND (whiz > "in\\"valid") AND (frob != "in\\"valid")', $select->toSQL());
67 public function testGroupByPlain() {
68 $select = CRM_Utils_SQL_Select
::from('foo')
70 ->groupBy(array('whiz_id*2', 'lower(bang)'));
71 $this->assertLike('SELECT * FROM foo GROUP BY bar_id, whiz_id*2, lower(bang)', $select->toSQL());
74 public function testHavingPlain() {
75 $select = CRM_Utils_SQL_Select
::from('foo')
77 ->having('count(id) > 2')
78 ->having(array('sum(id) > 10', 'avg(id) < 200'));
79 $this->assertLike('SELECT * FROM foo GROUP BY bar_id HAVING (count(id) > 2) AND (sum(id) > 10) AND (avg(id) < 200)', $select->toSQL());
82 public function testHavingArg() {
83 $select = CRM_Utils_SQL_Select
::from('foo')
85 ->having('count(id) > #mincnt', array('#mincnt' => 2))
86 ->having(array('sum(id) > #whiz', 'avg(id) < #whiz'), array('#whiz' => 10));
87 $this->assertLike('SELECT * FROM foo GROUP BY bar_id HAVING (count(id) > 2) AND (sum(id) > 10) AND (avg(id) < 10)', $select->toSQL());
90 public function testOrderByPlain() {
91 $select = CRM_Utils_SQL_Select
::from('foo bar')
92 ->orderBy('first asc')
93 ->orderBy(array('second desc', 'third'));
94 $this->assertLike('SELECT * FROM foo bar ORDER BY first asc, second desc, third', $select->toSQL());
97 public function testLimit_defaultOffset() {
98 $select = CRM_Utils_SQL_Select
::from('foo bar')
100 $this->assertLike('SELECT * FROM foo bar LIMIT 20 OFFSET 0', $select->toSQL());
103 public function testLimit_withOffset() {
104 $select = CRM_Utils_SQL_Select
::from('foo bar')
106 $this->assertLike('SELECT * FROM foo bar LIMIT 20 OFFSET 60', $select->toSQL());
109 public function testLimit_disable() {
110 $select = CRM_Utils_SQL_Select
::from('foo bar')
113 $this->assertLike('SELECT * FROM foo bar', $select->toSQL());
116 public function testModeOutput() {
117 $select = CRM_Utils_SQL_Select
::from('foo', array('mode' => 'out'))
118 ->where('foo = @value')
123 ->param('@value', 'not"valid')
125 '@base' => 'in"valid',
127 $this->assertLike('SELECT * FROM foo WHERE (foo = "not\\"valid") AND (whiz > "in\\"valid") AND (frob != "in\\"valid")', $select->toSQL());
130 CRM_Utils_SQL_Select
::from('foo', array('mode' => 'out'))
131 ->where('foo = @value', array('@value' => 'not"valid'));
132 $this->fail('In output mode, we should reject requests to interpolate inputs.');
134 catch (Exception
$e) {
135 $this->assertRegExp("/Cannot mix interpolation modes/", $e->getMessage());
138 $outputModeFragment = CRM_Utils_SQL_Select
::fragment()
139 ->param('value', 'whatever');
140 $inputModeFragment = CRM_Utils_SQL_Select
::fragment()
141 ->where('foo = @value', array('@value' => 'not"valid'));
143 $outputModeFragment->merge($inputModeFragment);
144 $this->fail('In output-mode, we should reject requests to merge from input-mode.');
146 catch (Exception
$e) {
147 $this->assertRegExp("/Cannot merge queries that use different interpolation modes/", $e->getMessage());
151 public function testBig() {
152 $select = CRM_Utils_SQL_Select
::from('foo')
154 ->join('rel1', 'INNER JOIN rel1_table rel1 ON foo.id = rel1.foo_id')
155 ->join('rel2', 'LEFT JOIN rel2_table rel2 ON foo.id = rel2.foo_id')
156 ->where('foo.type = @theType', array('@theType' => 'mytype'))
158 ->having('sum(rel1.stat) > 10')
159 ->orderBy('rel2.whiz')
162 "SELECT foo.id FROM foo"
163 . " INNER JOIN rel1_table rel1 ON foo.id = rel1.foo_id"
164 . " LEFT JOIN rel2_table rel2 ON foo.id = rel2.foo_id "
165 . " WHERE (foo.type = \"mytype\")"
167 . " HAVING (sum(rel1.stat) > 10)"
168 . " ORDER BY rel2.whiz"
169 . " LIMIT 100 OFFSET 300",
175 * Parameter-values could include control characters like
176 * '"@" or "!", but they should never be evaluated.
178 public function testNoIterativeInterpolation() {
179 $select = CRM_Utils_SQL_Select
::from('foo')
180 ->where('a = @a and b = @b and c = @c', array(
185 $this->assertLike('SELECT * FROM foo WHERE (a = "@b" and b = "@c" and c = "@a")', $select->toSQL());
188 public function testInterpolate() {
189 $actual = CRM_Utils_SQL_Select
::from('ignore')->interpolate(
190 '@escaped !unescaped #validated',
192 '@escaped' => 'foo"bar',
193 '!unescaped' => 'concat(foo,bar)',
194 '#validated' => 15.2,
197 $this->assertLike('"foo\"bar" concat(foo,bar) 15.2', $actual);
200 public function testInterpolateWildcard() {
201 $actual = CRM_Utils_SQL_Select
::from('ignore')->interpolate(
202 'escaped @escaped unescaped !unescaped validated #validated',
204 'escaped' => 'foo"bar',
205 'unescaped' => 'concat(foo,bar)',
209 $this->assertLike('escaped "foo\"bar" unescaped concat(foo,bar) validated 15.2', $actual);
212 public function testInterpolateUnknown() {
213 $actual = CRM_Utils_SQL_Select
::from('ignore')->interpolate(
214 'escaped @escaped unescaped !unescaped validated #validated',
216 'irrelevant' => 'foo',
219 $this->assertLike('escaped @escaped unescaped !unescaped validated #validated', $actual);
222 public function testInterpolateUnknownStrict() {
224 CRM_Utils_SQL_Select
::from('ignore')
226 ->interpolate('@johnMcClane',
228 'irrelevant' => 'foo',
231 $this->fail('Unknown variables should throw errors in strict mode.');
233 catch (Exception
$e) {
234 $this->assertRegExp('/Cannot build query. Variable "@johnMcClane" is unknown./', $e->getMessage());
238 public function testInterpolateArray() {
239 $actual = CRM_Utils_SQL_Select
::from('ignore')->interpolate(
240 '(@escaped) (!unescaped) (#validated)',
242 '@escaped' => array('foo"bar', "whiz", "null", NULL, "bang"),
243 '!unescaped' => array('foo"bar', 'bar'),
244 '#validated' => array(1, 10, NULL, 100.1),
247 $this->assertLike('("foo\\"bar", "whiz", "null", NULL, "bang") (foo"bar, bar) (1, 10, NULL, 100.1)', $actual);
250 public function testInterpolateBadNumber() {
252 $result = CRM_Utils_SQL_Select
::from('ignore')->interpolate('#num', array(
253 '#num' => '5not-a-number5',
255 $this->fail('Expected exception; got: ' . var_export($result, TRUE));
257 catch (CRM_Core_Exception
$e) {
258 $this->assertTrue(TRUE, "Caught expected exception");
262 $result = CRM_Utils_SQL_Select
::from('ignore')->interpolate('#num', array(
263 '#num' => array(1, '5not-a-number5', 2),
265 $this->fail('Expected exception; got: ' . var_export($result, TRUE));
267 catch (CRM_Core_Exception
$e) {
268 $this->assertTrue(TRUE, "Caught expected exception");
272 public function testMerge() {
273 $fragmentOutMode = CRM_Utils_SQL_Select
::fragment()
274 ->select(array('a', 'b'))
277 $fragmentAutoMode = CRM_Utils_SQL_Select
::fragment()
280 $query = CRM_Utils_SQL_Select
::from('foo')
281 ->select(array('c', 'd'))
284 ->merge($fragmentOutMode)
285 ->merge($fragmentAutoMode);
286 $this->assertLike('SELECT c, d, a, b, e FROM foo WHERE (c = "4") AND (a = 2) AND (whipit())', $query->toSQL());
289 public function testArrayGet() {
290 $select = CRM_Utils_SQL_Select
::from("foo")
291 ->param('hello', 'world');
292 $this->assertEquals('world', $select['hello']);
295 public function testInsertInto_WithDupes() {
296 $select = CRM_Utils_SQL_Select
::from('foo')
297 ->insertInto('bar', array('first', 'second', 'third', 'fourth'))
302 ->where('!field = #value', array('field' => 'zoo', 'value' => 3))
303 ->where('!field = #value', array('field' => 'aviary', 'value' => 3))
304 ->where('!field = #value', array('field' => 'zoo', 'value' => 3))
305 ->groupBy('!colName', array('colName' => 'noodle'))
306 ->groupBy('!colName', array('colName' => 'sauce'))
307 ->groupBy('!colName', array('colName' => 'noodle'));
308 $this->assertLike('INSERT INTO bar (first, second, third, fourth) SELECT fid, 1, fid, 1 FROM foo WHERE (zoo = 3) AND (aviary = 3) GROUP BY noodle, sauce', $select->toSQL());
314 * @param string $message
316 public function assertLike($expected, $actual, $message = '') {
317 $expected = trim((preg_replace('/[ \r\n\t]+/', ' ', $expected)));
318 $actual = trim((preg_replace('/[ \r\n\t]+/', ' ', $actual)));
319 $this->assertEquals($expected, $actual, $message);