public function load($condition) { $condition = trim($condition); $e = $this->_tokenizer->sqlExplode($condition); if (count($e) > 2) { $expr = new Doctrine_Expression($e[0], $this->query->getConnection()); $e[0] = $expr->getSql(); $operator = $e[1]; if (substr(trim($e[2]), 0, 1) != '(') { $expr = new Doctrine_Expression($e[2], $this->query->getConnection()); $e[2] = $expr->getSql(); } // We need to check for agg functions here $hasLeftAggExpression = preg_match('/(.*)\\(([^\\)]*)\\)([\\)]*)/', $e[0], $leftMatches); if ($hasLeftAggExpression) { $e[0] = $leftMatches[2]; } $hasRightAggExpression = preg_match('/(.*)\\(([^\\)]*)\\)([\\)]*)/', $e[2], $rightMatches); if ($hasRightAggExpression) { $e[2] = $rightMatches[2]; } $a = explode('.', $e[0]); $field = array_pop($a); $reference = implode('.', $a); $value = $e[2]; $conn = $this->query->getConnection(); $alias = $this->query->getTableAlias($reference); $map = $this->query->getAliasDeclaration($reference); $table = $map['table']; // check if value is enumerated value $enumIndex = $table->enumIndex($field, trim($value, "'")); if (false !== $enumIndex && $conn->getAttribute(Doctrine::ATTR_USE_NATIVE_ENUM)) { $enumIndex = $conn->quote($enumIndex, 'text'); } if (substr($value, 0, 1) == '(') { // trim brackets $trimmed = $this->_tokenizer->bracketTrim($value); if (substr($trimmed, 0, 4) == 'FROM' || substr($trimmed, 0, 6) == 'SELECT') { // subquery found $q = $this->query->createSubquery(); $value = '(' . $q->parseQuery($trimmed)->getQuery() . ')'; } elseif (substr($trimmed, 0, 4) == 'SQL:') { $value = '(' . substr($trimmed, 4) . ')'; } else { // simple in expression found $e = $this->_tokenizer->sqlExplode($trimmed, ','); $value = array(); foreach ($e as $part) { $index = $table->enumIndex($field, trim($part, "'")); if (false !== $index && $conn->getAttribute(Doctrine::ATTR_USE_NATIVE_ENUM)) { $index = $conn->quote($index, 'text'); } if ($index !== false) { $value[] = $index; } else { $value[] = $this->parseLiteralValue($part); } } $value = '(' . implode(', ', $value) . ')'; } } else { if ($enumIndex !== false) { $value = $enumIndex; } else { $value = $this->parseLiteralValue($value); } } switch ($operator) { case '<': case '>': case '=': case '!=': if ($enumIndex !== false) { $value = $enumIndex; } default: $leftExpr = ($hasLeftAggExpression ? $leftMatches[1] . '(' : '') . $alias . '.' . $field . ($hasLeftAggExpression ? $leftMatches[3] . ')' : ''); $rightExpr = ($hasRightAggExpression ? $rightMatches[1] . '(' : '') . $value . ($hasRightAggExpression ? $rightMatches[3] . ')' : ''); $condition = $leftExpr . ' ' . $operator . ' ' . $rightExpr; } } return $condition; }
public function load($condition) { $condition = trim($condition); $e = $this->_tokenizer->sqlExplode($condition); if (($l = count($e)) > 2) { $leftExpr = $this->query->parseClause($e[0]); $operator = $e[1]; if ($l == 4) { // FIX: "field NOT IN (XXX)" issue // Related to ticket #1329 $operator .= ' ' . $e[2]; // Glue "NOT" and "IN" $e[2] = $e[3]; // Move "(XXX)" to previous index unset($e[3]); // Remove unused index } else { if ($l >= 5) { // FIX: "field BETWEEN field2 AND field3" issue // Related to ticket #1488 $e[2] .= ' ' . $e[3] . ' ' . $e[4]; unset($e[3], $e[4]); // Remove unused indexes } } if (substr(trim($e[2]), 0, 1) != '(') { $expr = new Doctrine_Expression($e[2], $this->query->getConnection()); $e[2] = $expr->getSql(); } // We need to check for agg functions here $rightMatches = array(); $hasRightAggExpression = $this->_processPossibleAggExpression($e[2], $rightMatches); // Defining needed information $value = $e[2]; if (substr($value, 0, 1) == '(') { // trim brackets $trimmed = $this->_tokenizer->bracketTrim($value); $trimmed_upper = strtoupper($trimmed); if (substr($trimmed_upper, 0, 4) == 'FROM' || substr($trimmed_upper, 0, 6) == 'SELECT') { // subquery found $q = $this->query->createSubquery()->parseQuery($trimmed, false); $value = '(' . $q->getSql() . ')'; $q->free(); } elseif (substr($trimmed_upper, 0, 4) == 'SQL:') { // Change due to bug "(" XXX ")" //$value = '(' . substr($trimmed, 4) . ')'; $value = substr($trimmed, 4); } else { // simple in expression found $e = $this->_tokenizer->sqlExplode($trimmed, ','); $value = array(); foreach ($e as $part) { $value[] = $this->parseLiteralValue($part); } $value = '(' . implode(', ', $value) . ')'; } } else { // Possible expression found (field1 AND field2) // In relation to ticket #1488 $e = $this->_tokenizer->bracketExplode($value, array(' AND ', ' \\&\\& '), '(', ')'); $value = array(); foreach ($e as $part) { $value[] = $this->parseLiteralValue($part); } $value = implode(' AND ', $value); } switch ($operator) { case '<': case '>': case '=': case '!=': default: $rightExpr = ($hasRightAggExpression ? $rightMatches[1] . '(' : '') . $value . ($hasRightAggExpression ? $rightMatches[3] . ')' : ''); $condition = $leftExpr . ' ' . $operator . ' ' . $rightExpr; } return $condition; } $parser = new Doctrine_Query_Where($this->query, $this->_tokenizer); return $parser->parse($condition); }
public function testExpressionParserSupportsParensInClauses() { $e = new Doctrine_Expression("CONCAT('(some)', '(one)')"); $this->assertEqual($e->getSql(), "CONCAT('(some)', '(one)')"); }