-
Notifications
You must be signed in to change notification settings - Fork 7.7k
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
Fix GH-12296: [odbc] [pdo_odbc] Optimized odbc connection string creating #12306
Fix GH-12296: [odbc] [pdo_odbc] Optimized odbc connection string creating #12306
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.
Without looking into the semantics as of now, there is something that caught my eye
The corrections to the indicated items have been completed. Please confirm this. |
The Db2i driver complains with
It generates a connection string like this:
Empty PWD= at the end seems to cause a syntax error with that driver. Manually adding
I think if the password is empty, it might be best to not include (Also, changes should be made to PDO_ODBC too, since the logic is really similar there.) |
Thank you.
It works with Sql server and FreeTDS, so it seems like a problem with Db2i. However, over the past few days, I have noticed that there are many cases where the detailed specifications of ODBC are slightly different, and I agree that it should be made as secure as possible.
If you do not set pwd when the password is empty, authentication will probably fail. It also expects the argument to be a string, so it won't pass null for reasons other than bugs.
ok, as soon as the policy is finalized, I will revise the PDO as well. I still don't understand it properly, but what kind of connection string did Db2i use to successfully authenticate? |
Yeah, finding out that drivers do parsing their own way every time is really annoying. The worst is when we're getting into a situation where two drivers basically do something where we have to have mutually exclusive behaviour for dealing with them. It almost makes me wish the connection string + appended username and password case was deprecated, and the interface matched ODBC's with a DSN+UID+PWD triplet or a connection string. It'd be a big breaking change though.
I think this might be driver specific, but again, there is the
For defining an empty password, |
My concern is that if you actually set the password to an empty string, you won't be able to authenticate unless you pass I'm currently setting up a docker environment to see how Db2i behaves. For reference, with SQL Server, it is possible to set an empty string for the password, although it requires some effort, so there is clearly a use case for this. I'm sorry if I misunderstood your point and said something off-topic. |
d1c1e03
to
389aa3f
Compare
Db2i requires an IBM i server, but you can use a public one like PUB400. Db2 LUW is a separate animal, but it'd be interesting to see how that one behaves (since I have to deal with it for CI, and it's different from Db2i).
That makes sense, though it annoyingly does conflict with "inherit the password from the DSN" case. If we want to have both cases, I'm thinking back to my previous comment of having null be different from an empty string (though I think a lot of existing code conflates the two?).
It's not a problem. The drivers aren't terribly consistent, so it's easy to get lost in the weeds. |
That's very useful information. Thank you!
Looking at the signatures of
Thank you. I've already gotten lost on this issue many times... |
Sorry, I was thinking of both odbc in PHP 7, as well as PDO right now (which it has a nullable string in the connection constructor for uid/pwd explicitly). |
I see now, no problem. At least, it seems like we don't have to worry about null on the master branch? |
It took a lot of effort, but I finally got the db2i environment set up and reproduced the behavior you described. |
I also confirmed the operation of db2 LUW. db2 LUW did not exhibit any strange behavior. Operation confirmed
|
If there is a semicolon at the end of the original dsn, the semicolon will be duplicated, so I modified it so that when adding a I also made a similar fix for pdo. |
@NattyNarwhal Also, it would be helpful if you could give us your opinion on whether these changes should be made to master or 8.2. |
For pdo, it was necessary to take null into account. I'll fix it later. |
done. |
Works with db2i driver; an empty password clearly states the driver is receiving an empty string as a password (and failing to authenticate, but desired behaviour for this PR). |
Thank you for confirmation! |
Dismissing review: not relevant anymore and letting someone else review it
All that's left is the problem, as you say, that passing an empty string as the password when establishing a connection that doesn't require a password causes an error. I think this can be achieved by making the credential argument optional, like pdo, and nullable, to distinguish between empty strings and null. Since this will require an RFC, I think it would be better to create and implement an RFC separately from this PR. |
IMHO it's a minor and isolated enough change that you probably don't need an RFC for it, but maybe others might disagree there. |
In case of doubt, you can ask the mailing list for potential complaints and check there if an RFC is needed. |
Thank you, I tried sending an email yesterday. |
Also, I’m still looking for opinions on the target branch. |
3c71354
to
3a50cf4
Compare
add test case fix test
3a50cf4
to
96faed4
Compare
Changed signature to nullable and optional. Now you can generate a dsn that does not include a password. I would be happy if you could try it when you have time. |
Works for me, the blank string and null paths both work in both extensions. FWIW once this gets merged, probably a good idea to update the (Note that IIRC, doc changes if it'll only be in the new release only get merged once the release starts to happen.) |
Thank you for confirmation! This is something we were discussing on the mailing list, could you please give me your opinion on whether master should be the target branch? |
We very rarely change signatures in patch versions so I'd say that it's best to target master. |
Yeah, I think that makes sense. Maybe it can be backported as a bug fix later if there's demand. |
Thank you! Also....there is no code owner for odbc and pdo_odbc, so I don't know if there is anyone else to ask for a review. |
I usually ask @cmb69 since he wrote most of the recent commits; he's also knowledge about SQL Server drivers w/ the extension though. |
@NattyNarwhal Christoph is not currently active in the PHP project. I'm not sure if there's somebody else who can review this. |
That's unfortunate. I might actually be in the best shape to review ODBC things, seeing as I've been submitting patches and triaging with end-user issues. |
I agree with that, thanks for see this. May I ask you to commit? |
I don't have merge access. I do a good job of making it seem like I do though 😵💫 |
Oops, excuse me! I mistakenly thought that all members had merge privileges.😳 Contributor Tim appears to have merge permissions, it's difficult to infer permissions from the label for me. |
I think someone else can merge, yes. I gave my LGTM earlier for them. (It'll be a bit annoying having to explain the new behaviour when 8.4 rolls out for my users, but it'll just be telling people to clean up their connect calls.) |
If you don't mind, could you take a look at 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.
This looks fine if @NattyNarwhal is Okay with it.
Minor comments
if (zend_parse_parameters(ZEND_NUM_ARGS(), "sss|l", &db, &db_len, &uid, &uid_len, &pwd, &pwd_len, &pv_opt) == FAILURE) { | ||
RETURN_THROWS(); | ||
} | ||
ZEND_PARSE_PARAMETERS_START(1, 4) | ||
Z_PARAM_STRING(db, db_len) | ||
Z_PARAM_OPTIONAL | ||
Z_PARAM_STRING_OR_NULL(uid, uid_len) | ||
Z_PARAM_STRING_OR_NULL(pwd, pwd_len) | ||
Z_PARAM_LONG(pv_opt) | ||
ZEND_PARSE_PARAMETERS_END(); |
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.
Why not just:
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s!s!l", &db, &db_len, &uid, &uid_len, &pwd, &pwd_len, &pv_opt) == FAILURE) {
?
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.
Thank you for confirmation.
I read this RFC and decided that odbc_connect()
is applicabled a "most often used function" when used in an application, so I thought I might as well rewrite it.
https://wiki.php.net/rfc/fast_zpp
If I'm wrong, I will rewrite it to use zend_parse_parameters
.
@@ -2095,32 +2095,55 @@ int odbc_sqlconnect(odbc_connection **conn, char *db, char *uid, char *pwd, int | |||
/* a connection string may have = but not ; - i.e. "DSN=PHP" */ | |||
if (strstr((char*)db, "=")) { | |||
direct = 1; | |||
|
|||
size_t db_len = strlen(db); |
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.
Add a comment above that this should be identical to the code in the PDO driver and vice versa
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.
Added in ad06797
Thank you merge! |
I did not edit upgrade and news🙏 |
This change caused a regression on nightly:
https://github.com/php/php-src/actions/runs/6758379815/job/18369962027 Can somebody have a look? |
@iluuu1994 It seems that the changes I made to the c file were completely unrelated, and the test case I added happened to cause this bug. This problem occurs when I close and connect again, like this:
To make CI quiet for now, remove all closes from tests. (Tests pass even without close.) I tried to see what would happen with (edit) |
Fixed the test to avoid the bug. |
Could be another issue with the MS driver if you can't identify where it could be in PHP; I ran into that before. |
Sorry, I posted by mistake |
fixes #12296
(edit) I also made a similar fix for pdo.
I'm wondering if I should make these changes to PHP 8.2.
With this change, several use cases such as those shown below can be handled successfully.
Correct credentials (my env):
Cases where the connection string contains only either uid or pwd:
Cases where both uppercase and lowercase letters are used in attribute keys:
cc: @NattyNarwhal
If we don't need a password, we shouldn't include it in our dsn. However, if the password is set to an empty string, we should include it in the dsn.
So to be able to differentiate between them, I changed it to make pwd nullable and not include it in dsn if null is specified.
If uid is included in dsn, the uid argument is completely useless, so I also changed uid to a similar specification.