Skip to content
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

inappropriate statement sharing #674

Closed

Conversation

igelbox
Copy link

@igelbox igelbox commented Oct 30, 2016

Add more parameter type checks into SimpleQuery.isPreparedFor for Oid.UNSPECIFIED parameter type.
This commit addresses issue #648

when parameter type changed
Check original parameter type when current parameter type is Oid.UNSPECIFIED.

fixes pgjdbc#648
@codecov-io
Copy link

codecov-io commented Oct 30, 2016

Current coverage is 64.12% (diff: 60.00%)

Merging #674 into master will increase coverage by 0.05%

@@             master       #674   diff @@
==========================================
  Files           165        164     -1   
  Lines         15129      15131     +2   
  Methods           0          0          
  Messages          0          0          
  Branches       2978       2982     +4   
==========================================
+ Hits           9694       9703     +9   
+ Misses         4201       4193     -8   
- Partials       1234       1235     +1   

Powered by Codecov. Last update f48c6bb...7938dce

Copy link
Member

@vlsi vlsi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update test code. Please add batch insert into t(...) values(?) kind of test.

insert values is needed for two reasons:

  1. test insert case;

  2. test how the fix plays with "insert batch rewritter".

PreparedStatement ps = con.prepareStatement("SELECT ?::timestamp");
try {
Timestamp ts = new Timestamp(1474997614836L);
for (int i = 0; i < 3; ++i) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is it required to have a loop here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because PreparedStatement is not cached after first executions. But after 5-th executions (which happens on 3-rd iteration) it become cached.

rs = ps.executeQuery();
try {
assertTrue(rs.next());
assertNull(rs.getObject(1));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please follow https://github.com/pgjdbc/pgjdbc/blob/master/CONTRIBUTING.md#test guidelines for writing tests and assertions

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I read the rules for the tests writing. But not figured, what I'm doing wrong.
Also, there is (into pgjdbc test classes) a lot of code that uses assertTrue for rs.next() and assertEquals without a message.

Copy link
Member

@vlsi vlsi Nov 25, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a lot of code that uses assertTrue for rs.next() and assertEquals without a message.

That is unfortunate. New code should explain what it is trying to test.
I agree assertTrue(rs.next()); might be fine (I would agree even with plain rs.next() without assert), however assertNull(rs.getObject(1)); should explain why does it expect null there.

The thing is when test fails, it takes lots of time to figure out what was the intention behind the test and why did it fail.
Having decent messages greatly reduces maintenance costs.

@igelbox igelbox force-pushed the issues/inappropriate-statement-sharing branch from 200061c to 534c05a Compare November 21, 2016 21:42
@igelbox
Copy link
Author

igelbox commented Nov 21, 2016

I added comments into the PreparedStatementTest#testInappropriateStatementSharing source code (for readability purposes).
Could you tell me, why should I add tests for data inserting, if this bug was already reproduced using select-statement? Or are you concerned about a lack of insert-statement tests?

rs = ps.executeQuery();
try {
assertTrue(rs.next());
assertNull(rs.getObject(1));
Copy link
Member

@vlsi vlsi Nov 25, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a lot of code that uses assertTrue for rs.next() and assertEquals without a message.

That is unfortunate. New code should explain what it is trying to test.
I agree assertTrue(rs.next()); might be fine (I would agree even with plain rs.next() without assert), however assertNull(rs.getObject(1)); should explain why does it expect null there.

The thing is when test fails, it takes lots of time to figure out what was the intention behind the test and why did it fail.
Having decent messages greatly reduces maintenance costs.

try {
assertTrue(rs.next());
// If an inappropriate caching occurred, then we'll get the data narrowing (TIMESTAMP -> DATE)
assertEquals(ts, rs.getObject(1));
Copy link
Member

@vlsi vlsi Nov 25, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment above this line should be moved into message argument of assertEquals. That would make error message much cleaner.

@igelbox
Copy link
Author

igelbox commented Nov 27, 2016

@vlsi thanks for you detailed answers.
I've added messages to assertNull and assertEquals methods.

@macobo
Copy link

macobo commented Dec 9, 2016

Ping on this - I think we might be running into this scenario under some rare conditions.

@vlsi vlsi added this to the 42.0.1 milestone Feb 12, 2017
@vlsi
Copy link
Member

vlsi commented May 3, 2017

I'm sorry to say that, however I need postpone the review to the release after 42.1.0.

@vlsi vlsi modified the milestones: 42.2.0, 42.1.0 May 3, 2017
@vlsi vlsi modified the milestones: 42.2.0, 42.2.1 Jan 16, 2018
@vlsi vlsi modified the milestones: 42.2.1, 42.2.2 Jan 23, 2018
@vlsi
Copy link
Member

vlsi commented Mar 8, 2018

I've been postponing this fix for quite a while now, and now I think the whole notion of "resolving parameter types" is odd (

params.setResolvedType(i + 1, queryOIDs[i]);
)
Current pgjdbc implementation parses the statement with Oid.UNSPECIFIED, receives the updated types from the backend and overwrites UNSPECIFIED with the DB results.

I would try the following approach:

  1. On bind/"isGoodFor" side, use exact oids specified by the client. For instance, if the statement was prepared for Oid.UNSPECIFIED, then the statement would suit for Oid.UNSPECIFIED parameter. After statement execution, backend might send more proper datatype for the bind (e.g. Oid.DATE), then Oid.DATE is good as well for the bind.

  2. On ParameterMetadata side, the types send by the DB should be used.

vlsi added a commit to vlsi/pgjdbc that referenced this pull request Mar 11, 2018
…ypes

timestamp, date, are sent as UNSPECIFIED, and pgjdbc did not verify the actual parameter types at parse time.
This might cause wrong results if the query was parsed with explicit type (e.g. setString(...)), and then re-executed with
TIMESTAMP parameter (timestamps are sent as UNSPECIFIED, thus pgjdbc silently accepted the statement even though it should reparse)

fixes pgjdbc#648
closes pgjdbc#674
@vlsi vlsi closed this in #1137 Mar 11, 2018
vlsi added a commit that referenced this pull request Mar 11, 2018
…ypes (#1137)

Timestamp, date (and some other types), are sent as UNSPECIFIED, and pgjdbc did not verify the actual parameter types at parse time.
This might cause wrong results if the query was parsed with explicit type (e.g. setString(...)), and then re-executed with
TIMESTAMP parameter (timestamps are sent as UNSPECIFIED, thus pgjdbc silently accepted the statement even though it should reparse)

fixes #648
closes #674
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants