-
Notifications
You must be signed in to change notification settings - Fork 2.5k
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
[DDC-2224] convertToDatabaseValueSQL() is not honored for DQL query parameters #574
Conversation
…arameters Fix + test
Hello, thank you for positing this Pull Request. I have automatically opened an issue on our Jira Bug Tracker for you with the details of this Pull-Request. See the Link: |
@@ -2072,6 +2072,12 @@ public function walkInputParameter($inputParam) | |||
{ | |||
$this->parserResult->addParameterMapping($inputParam->name, $this->sqlParamIndex++); | |||
|
|||
$parameter = $this->query->getParameter($inputParam->name); | |||
if ($parameter && Type::hasType($parameter->getType())) { |
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.
Missing newline before this line
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.
Also: this would fail on unknown types anyway. Is the check for Type::hasType
necessary?
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.
hasType does isset(self::$_typesMap[$name])
whereas getType throw DBALException::unknownColumnType($name)
if it's not found, so I guess the check is necessary and it will not fail if the type is not found.
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.
My point is that a failure on not found type is acceptable, but binding allows custom parameter type anyway... guess you're right :)
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.
OK I get it. Yes it's possible a user specify a wrong type in setParameter($key, $value, $type)
, in that case is it better to silently ignore the type given (actual) or have an error of type not found (if the check was removed)?
I'd go for the second actually.
Works like a charm for me, thanks! |
@@ -2072,6 +2072,13 @@ public function walkInputParameter($inputParam) | |||
{ | |||
$this->parserResult->addParameterMapping($inputParam->name, $this->sqlParamIndex++); | |||
|
|||
$parameter = $this->query->getParameter($inputParam->name); | |||
|
|||
if ($parameter && Type::hasType($parameter->getType())) { |
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 would advocate to remove the hasType()
test as well.
IMO, failing silently in the case of an unknown type is a bad idea!
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.
@BenMorel Not sure if it works with https://github.com/doctrine/dbal/blob/master/lib/Doctrine/DBAL/Connection.php#L69-L88
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.
@Ocramius I can't see why, can you explain?
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.
There are no db types 101
and 102
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.
Ok, you're right! I had not realized that you could use non-Type
types in the ORM as well (obviously....) so hasType()
is necessary.
However, it would be good to avoid failing silently if we pass an invalid type string. Maybe the following code would solve the problem:
if (is_string($parameter)) {
$parameterType = Type::getType($parameter->getType());
That would filter out all PDO_PARAM_*
and Connection::PARAM_*
integer values, as well as the NULL
value when the parameter does not exist.
By the way, should we accept getParameter()
to be NULL
as well?
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've double-checked the code, and it can only return null
if the parameter name does not exist for this query, which is an error IMO. So I'd change the code for:
$parameter = $this->query->getParameter($inputParam->name);
if (! $parameter) {
throw QueryException::unknownParameter($inputParam->name);
}
if (is_string($parameter->getType())) {
$parameterType = Type::getType($parameter->getType());
return $parameterType->convertToDatabaseValueSQL('?', $this->platform);
}
This code has an extra consequence then:
If your DQL contains a parameter such as :name
, and you don't call ->setParameter('name', ...)
, it will throw a QueryException. Right now, this is not the case. @beberlei , could you please comment on this?
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.
@BenMorel this is fine, just moving from PDOException to QueryException here
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.
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.
yes your code is better for this, i like it very much.
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.
The problem with this change is, that its breaking backwards compatibility, currently the following code is valid for a "datetime" field:
In the new approach it would lead to a fatal error, because the datetime Type expects a DateTime instance. I am wondering if the check should only transform if the value is an object. |
@beberlei Don't you mean this?
If the parameter type is not set (like in the example you gave), then the parameter type inferred will be "string" (cf. |
@beberlei Yes, with the example you gave, the type will actually be |
Edit: Wrong not merged into master. There is a problem with this patch and caching, which makes it unmergable: Passing a type into the parameters is not recognized during caching, that means, using a DQL cache, the same DQL statement with:
will lead to the same SQL being generated, depending on if the first or the second set parameter query is executed first. |
The conversion here has to be done in side the |
Just verified in the code, there is no way to fix this issue, you need to create a custom DQL function to allow this converting to work. |
@beberlei So we're just abandoning like that..? |
@BenMorel you can convert the values before putting them to |
+1 I really see that as a bug because it's really not the expected behavior for the end-user. Juste to be clear I'm not complaining about the fact that there's a bug, but the fact that it's closed as "Invalid" |
@beberlei It's not that easy, sometimes you rely on SQL functions such as geometry functions that are hard (and useless) to implement in PHP, and as @mnapoli pointed out, the current behaviour is not the one expected by the user of the ORM (the type behaves differently when persisting an entity as opposed to when querying entities with DQL). I must support the fact that it's a bit sad to close this is as Invalid, instead of leaving it open for further thought. |
The assumptions in this PR are completely wrong, how can i leave it open for thought? While looking at this issue i realized why it wasnt this way beforehand and this is because the context is unknown here for the SqlWalker, there is knowing if we want to convet or not. Additionally to
|
I was talking about the issue, not this PR in particular (I agree this wasn't the best place to talk about this, then). Because it's not feasible with how the ORM is currently architectured doesn't mean it's impossible, does it? My point is, leaving it open reminds us that this is an issue, and if someone rethinks the architecture in the future, he'll have that in mind as well to see if his new ideas fit all the needs (I know that there are other missing features in Doctrine such as value objects, and I suspect that these might bring similar issues). |
same for me, no problem with rejecting the PR (I didn't want to pollute too much the Jira issue with meta-discussions) |
I have a solution that could help. We could add a generic DQL function
This would then wrap around Would that help you two? |
TBH, I have already changed my code to not rely on this functionality anymore (my type doesn't need |
I'm not sure that would help much too, the main problem I have is that it's not symmetrical between entity insertion and querying, so that wouldn't help with that if I understand correctly. |
DDC-2224: convertToDatabaseValueSQL() is not honored for DQL query parameters
Fix + test
Please note this is the first time I get into SqlWalker, I hope I inserted the fix at the right place.