From 081904296c3fe858f77e4bd350dce6c1a5913233 Mon Sep 17 00:00:00 2001 From: cty123 Date: Sat, 24 Feb 2024 21:24:36 +0100 Subject: [PATCH] perf: add column name index mapping in PostgresqlRow class to avoid looping through the fields unnecessarily. [resolves #636] --- .../io/r2dbc/postgresql/PostgresqlRow.java | 31 ++++++++++++++++--- .../postgresql/PostgresqlRowUnitTests.java | 1 + 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/r2dbc/postgresql/PostgresqlRow.java b/src/main/java/io/r2dbc/postgresql/PostgresqlRow.java index 1fffcc473..2183e466e 100644 --- a/src/main/java/io/r2dbc/postgresql/PostgresqlRow.java +++ b/src/main/java/io/r2dbc/postgresql/PostgresqlRow.java @@ -24,6 +24,9 @@ import io.r2dbc.postgresql.message.backend.RowDescription; import io.r2dbc.postgresql.util.Assert; import io.r2dbc.spi.Row; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; import reactor.core.publisher.Mono; import reactor.util.annotation.Nullable; @@ -47,6 +50,8 @@ final class PostgresqlRow implements io.r2dbc.postgresql.api.PostgresqlRow { private volatile boolean isReleased = false; + private Map columnNameIndexCacheMap; + PostgresqlRow(ConnectionResources context, io.r2dbc.postgresql.api.PostgresqlRowMetadata metadata, List fields, ByteBuf[] data) { this.context = Assert.requireNonNull(context, "context must not be null"); this.metadata = Assert.requireNonNull(metadata, "metadata must not be null"); @@ -138,6 +143,15 @@ public String toString() { '}'; } + static Map createColumnNameIndexMap(List fields) { + Map columnNameIndexMap = new HashMap<>(fields.size() * 2); + for (int i = fields.size() - 1; i >= 0; i--) { + columnNameIndexMap.put(fields.get(i).getName().toLowerCase(Locale.US), i); + } + + return columnNameIndexMap; + } + static PostgresqlRow toRow(ConnectionResources context, DataRow dataRow, Codecs codecs, RowDescription rowDescription) { Assert.requireNonNull(dataRow, "dataRow must not be null"); Assert.requireNonNull(codecs, "rowDescription must not be null"); @@ -165,12 +179,19 @@ void release() { } private int getColumn(String name) { - for (int i = 0; i < this.fields.size(); i++) { - RowDescription.Field field = this.fields.get(i); + if (this.columnNameIndexCacheMap == null) { + this.columnNameIndexCacheMap = createColumnNameIndexMap(this.fields); + } - if (field.getName().equalsIgnoreCase(name)) { - return i; - } + Integer index = this.columnNameIndexCacheMap.get(name); + if (index != null) { + return index; + } + + index = this.columnNameIndexCacheMap.get(name.toLowerCase(Locale.US)); + if (index != null) { + this.columnNameIndexCacheMap.put(name, index); + return index; } throw new NoSuchElementException(String.format("Column name '%s' does not exist in column names %s", name, toColumnNames())); diff --git a/src/test/java/io/r2dbc/postgresql/PostgresqlRowUnitTests.java b/src/test/java/io/r2dbc/postgresql/PostgresqlRowUnitTests.java index e7c5fd424..203b25a4c 100644 --- a/src/test/java/io/r2dbc/postgresql/PostgresqlRowUnitTests.java +++ b/src/test/java/io/r2dbc/postgresql/PostgresqlRowUnitTests.java @@ -132,6 +132,7 @@ void getName() { .build(); assertThat(new PostgresqlRow(MockContext.builder().codecs(codecs).build(), new PostgresqlRowMetadata(Collections.emptyList()), this.columns, this.data).get("test-name-2", Object.class)).isSameAs(value); + assertThat(new PostgresqlRow(MockContext.builder().codecs(codecs).build(), new PostgresqlRowMetadata(Collections.emptyList()), this.columns, this.data).get("tEsT-nAme-2", Object.class)).isSameAs(value); } @Test