Skip to content

PartialSearchFilter: ESCAPE '\' causes ORA-01425 on Oracle #8434

Description

@FrancescoPileo

API Platform version(s) affected: 4.3.10
(api-platform/doctrine-orm / api-platform/symfony)

Description
ApiPlatform\Doctrine\Orm\Filter\PartialSearchFilter generates SQL LIKE expressions with ESCAPE '\'.

On Oracle this fails with:

ORA-01425: escape character must be character string of length 1

In the executed SQL the escape clause appears as ESCAPE '\\' / ESCAPE '\\\\' (depending on logging), which Oracle rejects because the escape character is not a single-character string.

This affects both case-sensitive and case-insensitive modes, since both append the same ESCAPE '\' clause.

How to reproduce

  1. Use API Platform 4.3.x with Doctrine ORM on an Oracle database.
  2. Configure a collection operation with PartialSearchFilter:
use ApiPlatform\Doctrine\Orm\Filter\PartialSearchFilter;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\QueryParameter;

new GetCollection(
    uriTemplate: '/items',
    parameters: [
        'name' => new QueryParameter(
            filter: new PartialSearchFilter(),
            property: 'name',
        ),
    ],
)
  1. Call:
GET /items?name=test
  1. Observe the generated SQL containing something like:
LOWER(o.name) LIKE LOWER(:name_p1) ESCAPE '\\'

and Oracle raising ORA-01425.

Relevant code in PartialSearchFilter:

$field.' LIKE :'.$parameterName.' ESCAPE \'\\\''
// and
'LOWER('.$field.') LIKE LOWER(:'.$parameterName.') ESCAPE \'\\\''

with:

private function formatLikeValue(string $value): string
{
    return '%'.addcslashes($value, '\\%_').'%';
}

Possible Solution
Make the escape character configurable (constructor option), and/or use a DB-agnostic escape character that Oracle accepts (e.g. !), updating both:

  • the ESCAPE '...' SQL clause
  • formatLikeValue() escaping of %, _, and the escape character itself

Example approach:

public function __construct(
    private readonly bool $caseSensitive = false,
    private readonly string $escapeCharacter = '\\',
) {}

Then for Oracle consumers:

new PartialSearchFilter(escapeCharacter: '!')

Alternatively, detect the database platform and choose a safe default escape character for Oracle.

Additional Context

  • Database: Oracle
  • Error: Doctrine\DBAL\Exception\DriverException wrapping ORA-01425
  • Workaround used locally: custom filter based on PartialSearchFilter, replacing \ with ! as escape character in both the SQL ESCAPE clause and value escaping.
  • Same issue likely impacts any environment where ESCAPE '\' is not treated as a single-character literal.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions