pgjdbc/pgjdbc GitHub issues and pull requests (mirror)
help / color / mirror / Atom feedFrom: davecramer (@davecramer) <[email protected]>
To: pgjdbc/pgjdbc <[email protected]>
Subject: Re: [pgjdbc/pgjdbc] issue #3757: PreparedStatement.toString() fails for bytea parameters with at least 42.7.7
Date: Tue, 12 Aug 2025 09:09:08 +0000
Message-ID: <[email protected]> (raw)
In-Reply-To: <[email protected]>
References: <[email protected]>
Amazon Q came up with the same code
After analyzing the Netty PR #9896, we can apply similar optimizations using lookup tables and bitwise operations. Here's the reworked version:
```java
if (value instanceof String) {
final String str = (String) value;
final int length = str.length();
// Fast fail if string is too short
if (length < 2 || str.charAt(0) != '\\' || str.charAt(1) != 'x') {
throw new IllegalArgumentException(GT.tr("bytea string parameters must be hex format"));
}
// Pre-calculate capacity: prefix('\x') + actual hex digits + suffix('::bytea')
final StringBuilder sb = new StringBuilder(length + 7); // Conservative estimate
sb.append("'\\x");
// Lookup table for hex validation - similar to Netty's approach
// Using byte[] instead of int[] as we only need 1 bit per entry
static final byte[] HEX_LOOKUP = new byte[256];
static {
// Initialize lookup table for hex characters
for (char c = '0'; c <= '9'; c++) HEX_LOOKUP[c] = 1;
for (char c = 'a'; c <= 'f'; c++) HEX_LOOKUP[c] = 1;
for (char c = 'A'; c <= 'F'; c++) HEX_LOOKUP[c] = 1;
}
int i = 2;
while (i < length) {
char c = str.charAt(i);
// Skip whitespace using bitwise operation
// Based on Netty's implementation
if ((c <= ' ' && ((1L << c) & ((1L << ' ') | (1L << '\t') | (1L << '\r') | (1L << '\n'))) != 0)) {
i++;
continue;
}
// Check if we have enough characters left
if (i + 2 > length) {
throw new IllegalArgumentException(GT.tr("Truncated bytea hex format"));
}
// Get hex digits
final char c1 = c;
final char c2 = str.charAt(i + 1);
// Validate hex digits using lookup table
if (c1 >= HEX_LOOKUP.length || HEX_LOOKUP[c1] == 0) {
throw new IllegalArgumentException(GT.tr("Invalid bytea hex format character {0}", c1));
}
if (c2 >= HEX_LOOKUP.length || HEX_LOOKUP[c2] == 0) {
throw new IllegalArgumentException(GT.tr("Invalid bytea hex format character {0}", c2));
}
sb.append(c1);
sb.append(c2);
i += 2;
}
sb.append("'::bytea");
return sb.toString();
}
```
Key improvements based on Netty's PR:
1. More efficient prefix check
- Direct char comparison instead of `startsWith()`
- Removes string allocation from `startsWith()`
2. Optimized whitespace checking
- Uses bitwise operations similar to Netty's implementation
- Single operation to check for all whitespace characters
- Avoids method call to `Character.isWhitespace()`
3. Better hex validation
- Static lookup table using byte[] for minimal memory footprint
- Single array bounds check and lookup instead of string search
- Byte array uses 1 bit effectively vs boolean array's 8 bits
- Table is shared across all instances
4. Removed separate counting pass
- StringBuilder will grow if needed
- Initial capacity is conservative estimate
- Trade-off between extra counting pass vs potential resize
5. Simplified loop structure
- Single while loop with continue for whitespace
- Reduced number of method calls
- More straightforward flow control
6. Memory efficiency
- Static lookup table shared across all instances
- No temporary object creation
- Minimal memory footprint for validation table
This implementation combines the best practices from both the original optimization and Netty's approaches:
- Uses Netty's efficient whitespace checking
- Employs lookup table for hex validation
- Maintains good readability while being highly optimized
- Reduces method calls and object creation
- Uses minimal memory for validation structures
The code should perform better than the original version while maintaining clear intent and good maintainability. As always, actual performance improvements should be verified through benchmarking in your specific use case.
view thread (17+ messages) latest in thread
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: github://pgjdbc/pgjdbc
Cc: [email protected], [email protected]
Subject: Re: [pgjdbc/pgjdbc] issue #3757: PreparedStatement.toString() fails for bytea parameters with at least 42.7.7
In-Reply-To: <<[email protected]>>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox