-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for Postgres positional parameters to Parser #6634
base: 4.3.x
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sweoggy, thanks for the patch, it looks good.
Besides the unit tests, could you add an integration test that demonstrate the usage of these parameters with PostgreSQL? It doesn't look like DBAL has ever supported them.
Also, the parser is a back port of the corresponding parser from PDO. It looks like at the time of the back port, it didn't support such parameters or I missed something. In any event, I want to keep its implementation close to PDO. If the support for these parameters was introduced in an newer PHP version, please update the link in the PHPDoc.
|
||
private const BACKTICK_IDENTIFIER = '`[^`]*`'; | ||
private const BRACKET_IDENTIFIER = '(?<!\b(?i:ARRAY))\[(?:[^\]])*\]'; | ||
private const MULTICHAR = ':{2,}'; | ||
private const NAMED_PARAMETER = ':[a-zA-Z0-9_]+'; | ||
private const POSITIONAL_PARAMETER = '(?<!\\?)\\?(?!\\?)'; | ||
private const POSITIONAL_PARAMETER = '((?<!\\?)\\?(?!\\?)|\\$\d+)'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to extract the new pattern into a separate constant?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so. Two arguments:
- This is Postgres' way of specifying positional parameters. So the naming makes a lot of sense.
- Adding an additional pattern would incur a performance penalty and complicate the code (having to add one more handler, which in turn just calls $visitor->acceptPositionalParameter($sql);)
9280a57
to
af9bf85
Compare
I believe this is a native pgsql driver feature, https://www.postgresql.org/docs/current/sql-expressions.html#SQL-EXPRESSIONS-PARAMETERS-POSITIONAL I just pushed a fix for re-occurring positional parameters and added an integration test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just realized it now that the SQL parser is used elsewhere than the wrapper statement and the oci8
driver – specifically, the pgsql
driver. I think it's fine for now but its purpose becomes less and less clear, so we may want to break it down into a few smaller ones to address #3744.
Since @derrabus is the original author of the pgsql
driver, I'd like him to review this patch as well.
As a second thought: if those are the placeholders natively recognized by the underlying driver, then why does it require a SQL parser in the DBAL implementation of the driver for them to work? So far, the parser has been used only in order to support the placeholders that the given component doesn't support natively.
tests/Functional/SQL/ParserTest.php
Outdated
|
||
public function testPostgresPlaceholders(): void | ||
{ | ||
if (! TestUtil::isDriverOneOf('pgsql')) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this test passes on pdo_pgsql
as well (not sure how it's implemented in PDO). Please move it into a dedicated test class and enable for pdo_pgsql
.
Since it's a functional test, it would be better to name it in a way that it reflects the functionality being tested (something about PostgreSQL native positional parameters). The parser is an implementation detail, which isn't always relevant (specifically, in the case of pdo_pgsql
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved it to a separate class. Tried to enable it for pdo_pgsql as well, but it actually doesn't work, it doesn't seem to pass the values to the query and instead tries to insert null values.
Not sure if this is a limitation of pdo_pgsql or further changes would be required to Doctrine to support positional parameters for this driver. Error can be seen here https://github.com/debricked/dbal/actions/runs/12137000213/job/33839318280
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems to be a limitation of PDO https://www.php.net/pdo.prepare
58de3d5
to
3332d96
Compare
The parser is currently used to translate the PDO-style positional parameters ( |
Regarding the second thought. This change is needed because Without this change, the Parser does not call |
That's my understanding as well. I believe that instead of making the parser support what the driver supports natively, a better approach would be to make the parser not get in the way of someone using the native parameters. The driver should not consider the parameter map derived from parsing the query the source of truth. It should only augment the native placeholders with the PDO-style ones. |
Summary
This PR enables using Postgres placeholders
$#
with doctrine/dbal. For example the following query work after this patch:Without this patch a driver exception is thrown:
Could not find parameter 1 in the SQL statement
.