Skip to content

Commit

Permalink
Reuse column index mapping from PostgresqlColumnMetadata.
Browse files Browse the repository at this point in the history
  • Loading branch information
cty123 authored and mp911de committed Mar 4, 2024
1 parent bbe3abf commit b6cac40
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 22 deletions.
22 changes: 10 additions & 12 deletions src/main/java/io/r2dbc/postgresql/PostgresqlRow.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,21 @@ final class PostgresqlRow implements io.r2dbc.postgresql.api.PostgresqlRow {

private volatile boolean isReleased = false;

private Map<String, Integer> columnNameIndexCacheMap;
private final Map<String, Integer> columnNameIndexCacheMap;

PostgresqlRow(ConnectionResources context, io.r2dbc.postgresql.api.PostgresqlRowMetadata metadata, List<RowDescription.Field> fields, ByteBuf[] data) {
this.context = Assert.requireNonNull(context, "context must not be null");
this.metadata = Assert.requireNonNull(metadata, "metadata must not be null");
this.fields = Assert.requireNonNull(fields, "fields must not be null");
this.data = Assert.requireNonNull(data, "data must not be null");

if (metadata instanceof PostgresqlRowMetadata) {
this.columnNameIndexCacheMap = Assert.requireNonNull(
((PostgresqlRowMetadata) metadata).getColumnNameIndexMap(),
"columnNameIndexCacheMap must not be null");
} else {
this.columnNameIndexCacheMap = createColumnNameIndexMap(this.fields);
}
}

@Override
Expand Down Expand Up @@ -179,18 +187,8 @@ void release() {
}

private int getColumn(String name) {
if (this.columnNameIndexCacheMap == null) {
this.columnNameIndexCacheMap = createColumnNameIndexMap(this.fields);
}

Integer index = this.columnNameIndexCacheMap.get(name);
if (index != null) {
return index;
}

index = this.columnNameIndexCacheMap.get(name.toLowerCase(Locale.ROOT));
Integer index = this.columnNameIndexCacheMap.get(name.toLowerCase(Locale.ROOT));
if (index != null) {
this.columnNameIndexCacheMap.put(name, index);
return index;
}

Expand Down
11 changes: 11 additions & 0 deletions src/main/java/io/r2dbc/postgresql/PostgresqlRowMetadata.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
Expand All @@ -42,14 +44,19 @@ final class PostgresqlRowMetadata extends AbstractCollection<String> implements

private final Map<String, PostgresqlColumnMetadata> nameKeyedColumns;

private final Map<String, Integer> columnNameIndexMap;

PostgresqlRowMetadata(List<PostgresqlColumnMetadata> columnMetadatas) {
this.columnMetadatas = Assert.requireNonNull(columnMetadatas, "columnMetadatas must not be null");
this.nameKeyedColumns = new LinkedHashMap<>();
this.columnNameIndexMap = new HashMap<>(columnMetadatas.size(), 1);

int i = 0;
for (PostgresqlColumnMetadata columnMetadata : columnMetadatas) {
if (!this.nameKeyedColumns.containsKey(columnMetadata.getName())) {
this.nameKeyedColumns.put(columnMetadata.getName(), columnMetadata);
}
columnNameIndexMap.putIfAbsent(columnMetadata.getName().toLowerCase(Locale.ROOT), i++);
}
}

Expand Down Expand Up @@ -183,6 +190,10 @@ PostgresqlColumnMetadata findColumn(String name) {
return column;
}

Map<String, Integer> getColumnNameIndexMap() {
return this.columnNameIndexMap;
}

static PostgresqlRowMetadata toRowMetadata(Codecs codecs, RowDescription rowDescription) {
Assert.requireNonNull(codecs, "codecs must not be null");
Assert.requireNonNull(rowDescription, "rowDescription must not be null");
Expand Down
27 changes: 17 additions & 10 deletions src/test/java/io/r2dbc/postgresql/PostgresqlRowUnitTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package io.r2dbc.postgresql;

import io.netty.buffer.ByteBuf;
import io.r2dbc.postgresql.codec.Codecs;
import io.r2dbc.postgresql.codec.MockCodecs;
import io.r2dbc.postgresql.message.backend.DataRow;
import io.r2dbc.postgresql.message.backend.RowDescription;
Expand All @@ -28,6 +29,7 @@
import java.util.Collections;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.stream.Collectors;

import static io.r2dbc.postgresql.message.Format.FORMAT_BINARY;
import static io.r2dbc.postgresql.message.Format.FORMAT_TEXT;
Expand All @@ -51,6 +53,11 @@ final class PostgresqlRowUnitTests {
new RowDescription.Field((short) 400, 400, 300, (short) 400, FORMAT_TEXT, "test-name-3", 500)
);

private final PostgresqlRowMetadata metadata = new PostgresqlRowMetadata(columns
.stream()
.map(field -> PostgresqlColumnMetadata.toColumnMetadata(mock(Codecs.class), field))
.collect(Collectors.toList()));

private final ByteBuf[] data = new ByteBuf[]{TEST.buffer(4).writeInt(100), TEST.buffer(4).writeInt(300), null};

@AfterEach
Expand Down Expand Up @@ -78,7 +85,7 @@ void getAfterRelease() {
.decoding(TEST.buffer(4).writeInt(300), 400, FORMAT_TEXT, Object.class, value)
.build();

PostgresqlRow row = new PostgresqlRow(MockContext.builder().codecs(codecs).build(), new PostgresqlRowMetadata(Collections.emptyList()), this.columns, new ByteBuf[0]);
PostgresqlRow row = new PostgresqlRow(MockContext.builder().codecs(codecs).build(), this.metadata, this.columns, new ByteBuf[0]);
row.release();

assertThatIllegalStateException().isThrownBy(() -> row.get("test-name-2", Object.class))
Expand All @@ -93,7 +100,7 @@ void getDefaultType() {
.decoding(TEST.buffer(4).writeInt(300), 400, FORMAT_TEXT, Object.class, value)
.build();

assertThat(new PostgresqlRow(MockContext.builder().codecs(codecs).build(), new PostgresqlRowMetadata(Collections.emptyList()), this.columns, this.data).get("test-name-2")).isSameAs(value);
assertThat(new PostgresqlRow(MockContext.builder().codecs(codecs).build(), this.metadata, this.columns, this.data).get("test-name-2")).isSameAs(value);
}

@Test
Expand All @@ -104,20 +111,20 @@ void getIndex() {
.decoding(TEST.buffer(4).writeInt(300), 400, FORMAT_TEXT, Object.class, value)
.build();

assertThat(new PostgresqlRow(MockContext.builder().codecs(codecs).build(), new PostgresqlRowMetadata(Collections.emptyList()), this.columns, this.data).get(1, Object.class)).isSameAs(value);
assertThat(new PostgresqlRow(MockContext.builder().codecs(codecs).build(), this.metadata, this.columns, this.data).get(1, Object.class)).isSameAs(value);
}

@Test
void getInvalidIndex() {
assertThatExceptionOfType(IndexOutOfBoundsException.class).isThrownBy(() -> new PostgresqlRow(MockContext.empty(), new PostgresqlRowMetadata(Collections.emptyList()), this.columns,
assertThatExceptionOfType(IndexOutOfBoundsException.class).isThrownBy(() -> new PostgresqlRow(MockContext.empty(), this.metadata, this.columns,
new ByteBuf[0]).get(3,
Object.class))
.withMessage("Column index 3 is larger than the number of columns 3");
}

@Test
void getInvalidName() {
assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(() -> new PostgresqlRow(MockContext.empty(), new PostgresqlRowMetadata(Collections.emptyList()), this.columns,
assertThatExceptionOfType(NoSuchElementException.class).isThrownBy(() -> new PostgresqlRow(MockContext.empty(), this.metadata, this.columns,
new ByteBuf[0]).get("test-name" +
"-4", Object.class))
.withMessageMatching("Column name 'test-name-4' does not exist in column names \\[test-name-[\\d], test-name-[\\d], test-name-[\\d]\\]");
Expand All @@ -131,20 +138,20 @@ void getName() {
.decoding(TEST.buffer(4).writeInt(300), 400, FORMAT_TEXT, Object.class, value)
.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);
assertThat(new PostgresqlRow(MockContext.builder().codecs(codecs).build(), this.metadata, this.columns, this.data).get("test-name-2", Object.class)).isSameAs(value);
assertThat(new PostgresqlRow(MockContext.builder().codecs(codecs).build(), this.metadata, this.columns, this.data).get("tEsT-nAme-2", Object.class)).isSameAs(value);
}

@Test
void getNoIdentifier() {
assertThatIllegalArgumentException().isThrownBy(() -> new PostgresqlRow(MockContext.empty(), new PostgresqlRowMetadata(Collections.emptyList()), this.columns, new ByteBuf[0]).get(null,
assertThatIllegalArgumentException().isThrownBy(() -> new PostgresqlRow(MockContext.empty(), this.metadata, this.columns, new ByteBuf[0]).get(null,
Object.class))
.withMessage("name must not be null");
}

@Test
void getNoType() {
assertThatIllegalArgumentException().isThrownBy(() -> new PostgresqlRow(MockContext.empty(), new PostgresqlRowMetadata(Collections.emptyList()), this.columns, new ByteBuf[0]).get("", null))
assertThatIllegalArgumentException().isThrownBy(() -> new PostgresqlRow(MockContext.empty(), this.metadata, this.columns, new ByteBuf[0]).get("", null))
.withMessage("type must not be null");
}

Expand All @@ -154,7 +161,7 @@ void getNull() {
.decoding(null, 400, FORMAT_TEXT, Object.class, null)
.build();

assertThat(new PostgresqlRow(MockContext.builder().codecs(codecs).build(), new PostgresqlRowMetadata(Collections.emptyList()), this.columns, this.data).get("test-name-3", Object.class)).isNull();
assertThat(new PostgresqlRow(MockContext.builder().codecs(codecs).build(), this.metadata, this.columns, this.data).get("test-name-3", Object.class)).isNull();
}

@Test
Expand Down

0 comments on commit b6cac40

Please sign in to comment.