1

I wrote a custom DQL function. In this function I use the same parameter twice:

public function getSql(SqlWalker $sqlWalker)
{
    $point1_lat = $this->point1_lat->dispatch($sqlWalker);
    $point1_lon = $this->point1_lon->dispatch($sqlWalker);
    $point2_lat = $this->point2_lat->dispatch($sqlWalker);
    $point2_lon = $this->point2_lon->dispatch($sqlWalker);

    $unitFactor = 6366.56486; // earth radius in km

    return "
        $unitFactor *
        2 * 
        ASIN(
            SQRT(
                POWER(
                    SIN(($point1_lat - $point2_lat) * pi()/180/2),
                    2
                ) + 
                COS($point1_lat * pi()/180) * 
                COS($point2_lat * pi()/180) * 
                POWER(
                    SIN(($point1_lon - $point2_lon) * pi()/180/2), 
                    2
                )
            )
        )
    ";
}

This is how the query is executed:

    $q = \App::get()->getEntityManager()->createQuery('
        SELECT
            s,
            GEO_DISTANCE(
                :lat, 
                :lng,
                s.glat,
                s.glng
            ) AS distance
        FROM
            \Application\Geo\Entity\Street s
    ');
    $q->setMaxResults(10);
    $q->setParameters(array(
        'lat' => 52.25948,
        'lng' => 6.76403,
    ));
    $result = $q->getResult();

This however gives me the following exception:

Message: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens

The following SQL is returned by getSql():

        6366.56486 *
        2 * 
        ASIN(
            SQRT(
                POWER(
                    SIN((? - g0_.glat) * pi()/180/2),
                    2
                ) + 
                COS(? * pi()/180) * 
                COS(g0_.glat * pi()/180) * 
                POWER(
                    SIN((? - g0_.glng) * pi()/180/2), 
                    2
                )
            )
        )

So I guess the exception is thrown because the named parameters are returned as indexed parameters. Is this a bug in doctrine or am I doing something wrong?

sroes
  • 14,663
  • 1
  • 53
  • 72

1 Answers1

0

This is not a bug, you can only use each parameter once, as the dispatch() function puts the value on the stack once, to match one ? placeholder in the query.

As a workaround, you can call dispatch() several times:

public function getSql(SqlWalker $sqlWalker)
{
    $point1_lat_a = $this->point1_lat->dispatch($sqlWalker);
    $point1_lat_b = $this->point1_lat->dispatch($sqlWalker);
    $point1_lon = $this->point1_lon->dispatch($sqlWalker);

    $point2_lat_a = $this->point2_lat->dispatch($sqlWalker);
    $point2_lat_b = $this->point2_lat->dispatch($sqlWalker);
    $point2_lon = $this->point2_lon->dispatch($sqlWalker);

    $unitFactor = 6366.56486; // earth radius in km

    return "
        $unitFactor *
        2 * 
        ASIN(
            SQRT(
                POWER(
                    SIN(($point1_lat_a - $point2_lat_a) * pi()/180/2),
                    2
                ) + 
                COS($point1_lat_b * pi()/180) * 
                COS($point2_lat_b * pi()/180) * 
                POWER(
                    SIN(($point1_lon - $point2_lon) * pi()/180/2), 
                    2
                )
            )
        )
    ";
}
BenMorel
  • 34,448
  • 50
  • 182
  • 322