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
perf: avoid string allocation for oid/rows parsing in command tag #1232
Merged
Merged
Changes from all commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
885554e
perf: Remove regex from interpretCommandStatus; replace with faster i…
jesperpedersen 87bdb86
perf: avoid string allocation for oid/rows parsing in command tag
vlsi d131205
style: correct assumption, document and fix toLong
vlsi 148a12a
docs: fix comment in toLong
vlsi ef425d3
refactor: move CommandStatus to a separate class, add tests
vlsi 7c7d03c
perf: reuse CommandCompleteParser to avoid memory allocation
vlsi 9b410fc
style: rearrange comments in CommandCompleteParser
vlsi 3590a18
style: add javadoc to isDigitAt, digitAt
vlsi cf60fee
style: checkstyle
vlsi 170fef9
style: rows->count, we're have, a isDigit
vlsi 0f02b32
style: adjust comment for NumberFormatException
vlsi 8313c0e
style: visibility/final
vlsi 44c3d5d
test: add more tests for CommandCompleteParser
vlsi db91492
style: revert changes to a translated string
vlsi File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
108 changes: 108 additions & 0 deletions
108
pgjdbc/src/main/java/org/postgresql/core/CommandCompleteParser.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
/* | ||
* Copyright (c) 2018, PostgreSQL Global Development Group | ||
* See the LICENSE file in the project root for more information. | ||
*/ | ||
|
||
package org.postgresql.core; | ||
|
||
import org.postgresql.util.GT; | ||
import org.postgresql.util.PSQLException; | ||
import org.postgresql.util.PSQLState; | ||
|
||
/** | ||
* Parses {@code oid} and {@code rows} from a {@code CommandComplete (B)} message (end of Execute). | ||
*/ | ||
public final class CommandCompleteParser { | ||
private long oid; | ||
private long rows; | ||
|
||
public CommandCompleteParser() { | ||
} | ||
|
||
public long getOid() { | ||
return oid; | ||
} | ||
|
||
public long getRows() { | ||
return rows; | ||
} | ||
|
||
void set(long oid, long rows) { | ||
this.oid = oid; | ||
this.rows = rows; | ||
} | ||
|
||
/** | ||
* Parses {@code CommandComplete (B)} message. | ||
* Status is in the format of "COMMAND OID ROWS" where both 'OID' and 'ROWS' are optional | ||
* and COMMAND can have spaces within it, like CREATE TABLE. | ||
* | ||
* @param status COMMAND OID ROWS message | ||
* @throws PSQLException in case the status cannot be parsed | ||
*/ | ||
public void parse(String status) throws PSQLException { | ||
// Assumption: command neither starts nor ends with a digit | ||
if (!Parser.isDigitAt(status, status.length() - 1)) { | ||
set(0, 0); | ||
return; | ||
} | ||
|
||
// Scan backwards, while searching for a maximum of two number groups | ||
// COMMAND OID ROWS | ||
// COMMAND ROWS | ||
long oid = 0; | ||
long rows = 0; | ||
try { | ||
int lastSpace = status.lastIndexOf(' '); | ||
// Status ends with a digit => it is ROWS | ||
if (Parser.isDigitAt(status, lastSpace + 1)) { | ||
rows = Parser.parseLong(status, lastSpace + 1, status.length()); | ||
|
||
if (Parser.isDigitAt(status, lastSpace - 1)) { | ||
int penultimateSpace = status.lastIndexOf(' ', lastSpace - 1); | ||
if (Parser.isDigitAt(status, penultimateSpace + 1)) { | ||
oid = Parser.parseLong(status, penultimateSpace + 1, lastSpace); | ||
} | ||
} | ||
} | ||
} catch (NumberFormatException e) { | ||
// This should only occur if the oid or rows are out of 0..Long.MAX_VALUE range | ||
throw new PSQLException( | ||
GT.tr("Unable to parse the count in command completion tag: {0}.", status), | ||
PSQLState.CONNECTION_FAILURE, e); | ||
} | ||
set(oid, rows); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "CommandStatus{" | ||
+ "oid=" + oid | ||
+ ", rows=" + rows | ||
+ '}'; | ||
} | ||
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) { | ||
return true; | ||
} | ||
if (o == null || getClass() != o.getClass()) { | ||
return false; | ||
} | ||
|
||
CommandCompleteParser that = (CommandCompleteParser) o; | ||
|
||
if (oid != that.oid) { | ||
return false; | ||
} | ||
return rows == that.rows; | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
int result = (int) (oid ^ (oid >>> 32)); | ||
result = 31 * result + (int) (rows ^ (rows >>> 32)); | ||
return result; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
49 changes: 49 additions & 0 deletions
49
pgjdbc/src/test/java/org/postgresql/core/CommandCompleteParserNegativeTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
/* | ||
* Copyright (c) 2018, PostgreSQL Global Development Group | ||
* See the LICENSE file in the project root for more information. | ||
*/ | ||
|
||
package org.postgresql.core; | ||
|
||
import org.postgresql.util.PSQLException; | ||
|
||
import org.junit.Assert; | ||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
import org.junit.runners.Parameterized; | ||
|
||
import java.util.Arrays; | ||
|
||
@RunWith(Parameterized.class) | ||
public class CommandCompleteParserNegativeTest { | ||
|
||
@Parameterized.Parameter(0) | ||
public String input; | ||
|
||
@Parameterized.Parameters(name = "input={0}") | ||
public static Iterable<Object[]> data() { | ||
return Arrays.asList(new Object[][]{ | ||
{"SELECT 0_0 42"}, | ||
{"SELECT 42 0_0"}, | ||
{"SELECT 0_0 0_0"}, | ||
}); | ||
} | ||
|
||
@Test | ||
public void run() throws PSQLException { | ||
CommandCompleteParser parser = new CommandCompleteParser(); | ||
try { | ||
parser.parse(input); | ||
Assert.fail("CommandCompleteParser should throw NumberFormatException for " + input); | ||
} catch (PSQLException e) { | ||
Throwable cause = e.getCause(); | ||
if (cause == null) { | ||
throw e; | ||
} | ||
if (!(cause instanceof NumberFormatException)) { | ||
throw e; | ||
} | ||
// NumerFormatException is expected | ||
} | ||
} | ||
} |
58 changes: 58 additions & 0 deletions
58
pgjdbc/src/test/java/org/postgresql/core/CommandCompleteParserTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
/* | ||
* Copyright (c) 2018, PostgreSQL Global Development Group | ||
* See the LICENSE file in the project root for more information. | ||
*/ | ||
|
||
package org.postgresql.core; | ||
|
||
import org.postgresql.util.PSQLException; | ||
|
||
import org.junit.Assert; | ||
import org.junit.Test; | ||
import org.junit.runner.RunWith; | ||
import org.junit.runners.Parameterized; | ||
|
||
import java.util.Arrays; | ||
|
||
@RunWith(Parameterized.class) | ||
public class CommandCompleteParserTest { | ||
|
||
@Parameterized.Parameter(0) | ||
public String input; | ||
@Parameterized.Parameter(1) | ||
public long oid; | ||
@Parameterized.Parameter(2) | ||
public long rows; | ||
|
||
@Parameterized.Parameters(name = "input={0}, oid={1}, rows={2}") | ||
public static Iterable<Object[]> data() { | ||
return Arrays.asList(new Object[][]{ | ||
{"SELECT 0", 0, 0}, | ||
{"SELECT -42", 0, 0}, | ||
{"SELECT", 0, 0}, | ||
{"", 0, 0}, | ||
{"A", 0, 0}, | ||
{"SELECT 42", 0, 42}, | ||
{"UPDATE 43 42", 43, 42}, | ||
{"UPDATE 43 " + Long.MAX_VALUE, 43, Long.MAX_VALUE}, | ||
{"UPDATE " + Long.MAX_VALUE + " " + Long.MAX_VALUE, Long.MAX_VALUE, Long.MAX_VALUE}, | ||
{"UPDATE " + (Long.MAX_VALUE / 10) + " " + (Long.MAX_VALUE / 10), (Long.MAX_VALUE / 10), | ||
(Long.MAX_VALUE / 10)}, | ||
{"UPDATE " + (Long.MAX_VALUE / 100) + " " + (Long.MAX_VALUE / 100), (Long.MAX_VALUE / 100), | ||
(Long.MAX_VALUE / 100)}, | ||
{"CREATE TABLE " + (Long.MAX_VALUE / 100) + " " + (Long.MAX_VALUE / 100), | ||
(Long.MAX_VALUE / 100), (Long.MAX_VALUE / 100)}, | ||
{"CREATE TABLE", 0, 0}, | ||
{"CREATE OR DROP OR DELETE TABLE 42", 0, 42}, | ||
}); | ||
} | ||
|
||
@Test | ||
public void run() throws PSQLException { | ||
CommandCompleteParser expected = new CommandCompleteParser(); | ||
CommandCompleteParser actual = new CommandCompleteParser(); | ||
expected.set(oid, rows); | ||
actual.parse(input); | ||
Assert.assertEquals(input, expected, actual); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Should return here, 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.
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.
apparently there isn't a test case for 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.
apparently, there is: https://github.com/pgjdbc/pgjdbc/blob/e0fb1c05e525cc2858f98a3e322c5eb4d982253e/pgjdbc/src/test/java/org/postgresql/core/CommandCompleteParserTest.java#L41
It just does not hurt
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 is not really valid, but something like CREATE 2ABLE would have failed previously.