zendframework / zend-db

Db component from Zend Framework
BSD 3-Clause "New" or "Revised" License
101 stars 122 forks source link

Expression placeholder exception #374

Closed slifin closed 4 years ago

slifin commented 5 years ago

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: https://github.com/zendframework/zend-db/pull/112/commits/d8d096c08de0c37cc96b6b91da652f42e06a9194 Strict checking introduced here: https://github.com/zendframework/zend-db/commit/4ce85654736c32d13c0f55cbcbd1884207690a78

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 https://github.com/zendframework/zend-db/pull/112/commits/d8d096c08de0c37cc96b6b91da652f42e06a9194 checks for)

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

slifin commented 5 years ago

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?

michalbundyra commented 5 years ago

@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.

slifin commented 5 years ago

Thank you, should I make a separate issue?