zendframework/zend-db

Expression placeholder exception

slifin opened this issue · 3 comments

Provide a narrative description of what you are trying to accomplish.
Trying to create an expression with named parameters

Code to reproduce the issue

$expression =
    new Expression(':a + :b', [':a' => 1, ':b' => 1]);

(new Select())
    ->columns([$expression]);

Expected results

SELECT 1 + 1 AS Expression1

Actual results

Zend\Db\Sql\Exception\RuntimeException: The number of replacements in the expression does not match the number of parameters
in /vendor/zendframework/zend-db/src/Sql/Expression.php on line 151

Context

Original code was introduced here:
d8d096c
Strict checking introduced here:
4ce8565

Possible Solution

Seems like the regex check on this line:
https://github.com/zendframework/zend-db/blob/master/src/Sql/Expression.php#L149
should be compared with !== not ===

The other thing that would need to be considered is the same placeholder being used in multiple placeholders (which is what the test in d8d096c checks for)

Maybe retrieve all placeholders from string with regex then array_unique them then count them?

After applying the fix for this (3a98cea) to my own local copy of zend-db

I get the following result:

SELECT :a + :b AS Expression1

from:

$expression =
    new Expression(':a + :b', [':a' => 1, ':b' => 2]);

$select = new Select();
$select->columns([$expression]);

Instead of what I expected:

SELECT 1 + 2 AS Expression1

Can any one else confirm?

@slifin I've checked and it is like that, but I think it is separate issue.
Converting expression with named parameters to string is not working properly... And it looks there is no any tests around it.

The test case:

    public function testIntegrationWithSelect()
    {
        $expression = new Expression(':a + :b', ['a' => 1, 'b' => 2]);

        $select = new Select();
        $select->columns([$expression]);

        self::assertSame(
            'SELECT 1 + 2 AS Expression1',
            $select->getSqlString(new TrustingSql92Platform())
        );
    }

and the result:

Failed asserting that two strings are identical.
Expected :'SELECT 1 + 2 AS Expression1'
Actual   :'SELECT :a + :b AS Expression1'

I will have a look on it in free time.

Thank you, should I make a separate issue?