/** * Receives a TupleExpression and changes it so that it conforms to this * SQL dialect. * * It transforms expressions looking like '(a, b) IN ((c, d), (e, f)' into an * equivalent expression of the form '((a = c) AND (b = d)) OR ((a = e) AND (b = f))'. * * It can also transform transform expressions where the right hand side is a query * selecting the same amount of columns as the elements in the left hand side of * the expression: * * (a, b) IN (SELECT c, d FROM a_table) is transformed into * * 1 = (SELECT 1 FROM a_table WHERE (a = c) AND (b = d)) * * @param \Cake\Database\Expression\TupleComparison $expression The expression to transform * @param \Cake\Database\Query $query The query to update. * @return void */ protected function _transformTupleComparison(TupleComparison $expression, $query) { $fields = $expression->getField(); if (!is_array($fields)) { return; } $value = $expression->getValue(); $op = $expression->getOperator(); $true = new QueryExpression('1'); if ($value instanceof Query) { $selected = array_values($value->clause('select')); foreach ($fields as $i => $field) { $value->andWhere([$field . " {$op}" => new IdentifierExpression($selected[$i])]); } $value->select($true, true); $expression->setField($true); $expression->setOperator('='); return; } $surrogate = $query->connection()->newQuery()->select($true); if (!is_array(current($value))) { $value = [$value]; } foreach ($value as $tuple) { $surrogate->orWhere(function ($exp) use($fields, $tuple) { foreach (array_values($tuple) as $i => $value) { $exp->add([$fields[$i] => $value]); } return $exp; }); } $expression->setField($true); $expression->setValue($surrogate); $expression->setOperator('='); }