Skip to content

Commit 5094a55

Browse files
authored
perf: use static binders for paramter values (GoogleCloudPlatform#4363)
Use a static bind method for all parameter values. This reduces garbage collection pressure, as it does not create a Parser instance for each parameter value that is assigned.
1 parent 5cb2e5d commit 5094a55

16 files changed

Lines changed: 454 additions & 181 deletions

src/main/java/com/google/cloud/spanner/pgadapter/parsers/ArrayParser.java

Lines changed: 54 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -345,76 +345,112 @@ protected byte[] binaryParse() {
345345
}
346346
}
347347

348+
public static void bind(
349+
ImmutableMap.Builder<String, Value> parametersBuilder,
350+
String name,
351+
byte[] item,
352+
int oidType,
353+
FormatCode formatCode,
354+
SessionState sessionState) {
355+
int elementOid = Parser.getArrayElementOid(oidType);
356+
List<?> list;
357+
if (item == null) {
358+
list = null;
359+
} else {
360+
switch (formatCode) {
361+
case TEXT:
362+
list =
363+
stringArrayToList(
364+
new String(item, StandardCharsets.UTF_8), elementOid, sessionState, false);
365+
break;
366+
case BINARY:
367+
list = binaryArrayToList(item, false);
368+
break;
369+
default:
370+
throw new IllegalArgumentException("Unsupported format: " + formatCode);
371+
}
372+
}
373+
bind(parametersBuilder, name, list, elementOid);
374+
}
375+
348376
@SuppressWarnings("unchecked")
349-
@Override
350-
public void bind(ImmutableMap.Builder<String, Value> parametersBuilder, String name) {
377+
public static void bind(
378+
ImmutableMap.Builder<String, Value> parametersBuilder,
379+
String name,
380+
List<?> list,
381+
int elementOid) {
351382
switch (elementOid) {
352383
case Oid.BIT:
353384
case Oid.BOOL:
354-
parametersBuilder.put(name, Value.boolArray((List<Boolean>) this.item));
385+
parametersBuilder.put(name, Value.boolArray((List<Boolean>) list));
355386
break;
356387
case Oid.INT2:
357-
if (this.item == null) {
388+
if (list == null) {
358389
parametersBuilder.put(name, Value.int64Array((long[]) null));
359390
} else {
360391
parametersBuilder.put(
361392
name,
362393
Value.int64Array(
363-
((List<Short>) this.item)
394+
((List<Short>) list)
364395
.stream()
365396
.map(s -> s == null ? null : s.longValue())
366397
.collect(Collectors.toList())));
367398
}
368399
break;
369400
case Oid.INT4:
370-
if (this.item == null) {
401+
if (list == null) {
371402
parametersBuilder.put(name, Value.int64Array((long[]) null));
372403
} else {
373404
parametersBuilder.put(
374405
name,
375406
Value.int64Array(
376-
((List<Integer>) this.item)
407+
((List<Integer>) list)
377408
.stream()
378409
.map(i -> i == null ? null : i.longValue())
379410
.collect(Collectors.toList())));
380411
}
381412
break;
382413
case Oid.INT8:
383-
parametersBuilder.put(name, Value.int64Array((List<Long>) this.item));
414+
parametersBuilder.put(name, Value.int64Array((List<Long>) list));
384415
break;
385416
case Oid.OID:
386-
parametersBuilder.put(name, Value.pgOidArray((List<Long>) this.item));
417+
parametersBuilder.put(name, Value.pgOidArray((List<Long>) list));
387418
break;
388419
case Oid.NUMERIC:
389-
parametersBuilder.put(name, Value.pgNumericArray((List<String>) this.item));
420+
parametersBuilder.put(name, Value.pgNumericArray((List<String>) list));
390421
break;
391422
case Oid.FLOAT4:
392-
parametersBuilder.put(name, Value.float32Array((List<Float>) this.item));
423+
parametersBuilder.put(name, Value.float32Array((List<Float>) list));
393424
break;
394425
case Oid.FLOAT8:
395-
parametersBuilder.put(name, Value.float64Array((List<Double>) this.item));
426+
parametersBuilder.put(name, Value.float64Array((List<Double>) list));
396427
break;
397428
case Oid.UUID:
398429
case Oid.VARCHAR:
399430
case Oid.TEXT:
400-
parametersBuilder.put(name, Value.stringArray((List<String>) this.item));
431+
parametersBuilder.put(name, Value.stringArray((List<String>) list));
401432
break;
402433
case Oid.JSONB:
403-
parametersBuilder.put(name, Value.pgJsonbArray((List<String>) this.item));
434+
parametersBuilder.put(name, Value.pgJsonbArray((List<String>) list));
404435
break;
405436
case Oid.BYTEA:
406-
parametersBuilder.put(name, Value.bytesArray((List<ByteArray>) this.item));
437+
parametersBuilder.put(name, Value.bytesArray((List<ByteArray>) list));
407438
break;
408439
case Oid.TIMESTAMPTZ:
409440
case Oid.TIMESTAMP:
410-
parametersBuilder.put(name, Value.timestampArray((List<Timestamp>) this.item));
441+
parametersBuilder.put(name, Value.timestampArray((List<Timestamp>) list));
411442
break;
412443
case Oid.DATE:
413-
parametersBuilder.put(name, Value.dateArray((List<Date>) this.item));
444+
parametersBuilder.put(name, Value.dateArray((List<Date>) list));
414445
break;
415446
default:
416447
throw PGExceptionFactory.newPGException(
417-
"Unsupported array element type: " + arrayElementType, SQLState.InvalidParameterValue);
448+
"Unsupported array element type: " + elementOid, SQLState.InvalidParameterValue);
418449
}
419450
}
451+
452+
@Override
453+
public void bind(ImmutableMap.Builder<String, Value> parametersBuilder, String name) {
454+
bind(parametersBuilder, name, this.item, this.elementOid);
455+
}
420456
}

src/main/java/com/google/cloud/spanner/pgadapter/parsers/BinaryParser.java

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -50,23 +50,27 @@ public class BinaryParser extends Parser<ByteArray> {
5050
}
5151

5252
BinaryParser(byte[] item, FormatCode formatCode) {
53-
if (item != null) {
54-
switch (formatCode) {
55-
case TEXT:
56-
try {
57-
this.item = ByteArray.copyFrom(PGbytea.toBytes(item));
58-
break;
59-
} catch (Exception exception) {
60-
throw PGExceptionFactory.newPGException(
61-
"Invalid binary value: " + new String(item, StandardCharsets.UTF_8),
62-
SQLState.SyntaxError);
63-
}
64-
case BINARY:
65-
this.item = toByteArray(item);
66-
break;
67-
default:
68-
throw new IllegalArgumentException("Unsupported format: " + formatCode);
69-
}
53+
this.item = toByteArray(item, formatCode);
54+
}
55+
56+
/** Converts the given data to a {@link ByteArray} based on the format code. */
57+
public static ByteArray toByteArray(byte[] item, FormatCode formatCode) {
58+
if (item == null) {
59+
return null;
60+
}
61+
switch (formatCode) {
62+
case TEXT:
63+
try {
64+
return ByteArray.copyFrom(PGbytea.toBytes(item));
65+
} catch (Exception exception) {
66+
throw PGExceptionFactory.newPGException(
67+
"Invalid binary value: " + new String(item, StandardCharsets.UTF_8),
68+
SQLState.SyntaxError);
69+
}
70+
case BINARY:
71+
return toByteArray(item);
72+
default:
73+
throw new IllegalArgumentException("Unsupported format: " + formatCode);
7074
}
7175
}
7276

@@ -182,6 +186,14 @@ static int base64ByteLength(String base64) {
182186
return length;
183187
}
184188

189+
public static void bind(
190+
ImmutableMap.Builder<String, Value> parametersBuilder,
191+
String name,
192+
byte[] item,
193+
FormatCode formatCode) {
194+
parametersBuilder.put(name, Value.bytes(toByteArray(item, formatCode)));
195+
}
196+
185197
@Override
186198
public void bind(ImmutableMap.Builder<String, Value> parametersBuilder, String name) {
187199
parametersBuilder.put(name, Value.bytes(this.item));

src/main/java/com/google/cloud/spanner/pgadapter/parsers/DateParser.java

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -45,25 +45,27 @@ public class DateParser extends Parser<Date> {
4545
}
4646

4747
DateParser(byte[] item, FormatCode formatCode) {
48-
if (item != null) {
49-
switch (formatCode) {
50-
case TEXT:
51-
String stringValue = new String(item, UTF8);
52-
// Use the first 10 characters of the date string, as the string might contain a timezone
53-
// identifier, which is not supported by parseDate(String).
54-
if (stringValue.length() >= 10) {
55-
this.item = Date.parseDate(stringValue.substring(0, 10));
56-
} else {
57-
throw PGExceptionFactory.newPGException(
58-
"Invalid date value: " + stringValue, SQLState.SyntaxError);
59-
}
60-
break;
61-
case BINARY:
62-
this.item = toDate(item);
63-
break;
64-
default:
65-
throw new IllegalArgumentException("Unsupported format: " + formatCode);
66-
}
48+
this.item = toDate(item, formatCode);
49+
}
50+
51+
/** Converts the given data to a {@link Date} based on the format code. */
52+
public static Date toDate(byte[] item, FormatCode formatCode) {
53+
if (item == null) {
54+
return null;
55+
}
56+
switch (formatCode) {
57+
case TEXT:
58+
String stringValue = new String(item, UTF8);
59+
if (stringValue.length() >= 10) {
60+
return Date.parseDate(stringValue.substring(0, 10));
61+
} else {
62+
throw PGExceptionFactory.newPGException(
63+
"Invalid date value: " + stringValue, SQLState.SyntaxError);
64+
}
65+
case BINARY:
66+
return toDate(item);
67+
default:
68+
throw new IllegalArgumentException("Unsupported format: " + formatCode);
6769
}
6870
}
6971

@@ -178,6 +180,14 @@ static int validateRange(long days) {
178180
return (int) days;
179181
}
180182

183+
public static void bind(
184+
ImmutableMap.Builder<String, Value> parametersBuilder,
185+
String name,
186+
byte[] item,
187+
FormatCode formatCode) {
188+
parametersBuilder.put(name, Value.date(toDate(item, formatCode)));
189+
}
190+
181191
@Override
182192
public void bind(ImmutableMap.Builder<String, Value> parametersBuilder, String name) {
183193
parametersBuilder.put(name, Value.date(this.item));

src/main/java/com/google/cloud/spanner/pgadapter/parsers/DoubleParser.java

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,22 @@ public class DoubleParser extends Parser<Double> {
4444
}
4545

4646
DoubleParser(byte[] item, FormatCode formatCode) {
47-
if (item != null) {
48-
switch (formatCode) {
49-
case TEXT:
50-
String stringValue = new String(item, StandardCharsets.UTF_8);
51-
this.item = parseDouble(stringValue);
52-
break;
53-
case BINARY:
54-
this.item = toDouble(item);
55-
break;
56-
default:
57-
throw new IllegalArgumentException("Unsupported format: " + formatCode);
58-
}
47+
this.item = toDouble(item, formatCode);
48+
}
49+
50+
/** Converts the given data to a double based on the format code. */
51+
public static Double toDouble(byte[] item, FormatCode formatCode) {
52+
if (item == null) {
53+
return null;
54+
}
55+
switch (formatCode) {
56+
case TEXT:
57+
String stringValue = new String(item, StandardCharsets.UTF_8);
58+
return parseDouble(stringValue);
59+
case BINARY:
60+
return toDouble(item);
61+
default:
62+
throw new IllegalArgumentException("Unsupported format: " + formatCode);
5963
}
6064
}
6165

@@ -103,6 +107,14 @@ public static byte[] convertToPG(
103107
}
104108
}
105109

110+
public static void bind(
111+
ImmutableMap.Builder<String, Value> parametersBuilder,
112+
String name,
113+
byte[] item,
114+
FormatCode formatCode) {
115+
parametersBuilder.put(name, toValue(toDouble(item, formatCode)));
116+
}
117+
106118
@Override
107119
public void bind(ImmutableMap.Builder<String, Value> parametersBuilder, String name) {
108120
parametersBuilder.put(name, toValue(this.item));

src/main/java/com/google/cloud/spanner/pgadapter/parsers/FloatParser.java

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,26 @@ public class FloatParser extends Parser<Float> {
4242
}
4343

4444
FloatParser(byte[] item, FormatCode formatCode) {
45-
if (item != null) {
46-
switch (formatCode) {
47-
case TEXT:
48-
String stringValue = new String(item);
49-
this.item = parseFloat(stringValue);
50-
break;
51-
case BINARY:
52-
this.item = ByteConverter.float4(item, 0);
53-
break;
54-
default:
55-
throw new IllegalArgumentException("Unsupported format: " + formatCode);
56-
}
45+
this.item = toFloat(item, formatCode);
46+
}
47+
48+
/** Converts the given data to a float based on the format code. */
49+
public static Float toFloat(byte[] item, FormatCode formatCode) {
50+
if (item == null) {
51+
return null;
52+
}
53+
switch (formatCode) {
54+
case TEXT:
55+
String stringValue = new String(item);
56+
return parseFloat(stringValue);
57+
case BINARY:
58+
if (item.length < 4) {
59+
throw SpannerExceptionFactory.newSpannerException(
60+
ErrorCode.INVALID_ARGUMENT, "Invalid length for float4: " + item.length);
61+
}
62+
return ByteConverter.float4(item, 0);
63+
default:
64+
throw new IllegalArgumentException("Unsupported format: " + formatCode);
5765
}
5866
}
5967

@@ -100,6 +108,14 @@ public static byte[] convertToPG(
100108
}
101109
}
102110

111+
public static void bind(
112+
ImmutableMap.Builder<String, Value> parametersBuilder,
113+
String name,
114+
byte[] item,
115+
FormatCode formatCode) {
116+
parametersBuilder.put(name, toValue(toFloat(item, formatCode)));
117+
}
118+
103119
@Override
104120
public void bind(ImmutableMap.Builder<String, Value> parametersBuilder, String name) {
105121
parametersBuilder.put(name, toValue(this.item));

0 commit comments

Comments
 (0)