diff --git a/src/main/java/org/mariadb/r2dbc/api/MariadbOutParameters.java b/src/main/java/org/mariadb/r2dbc/api/MariadbOutParameters.java deleted file mode 100644 index 901ed4ca..00000000 --- a/src/main/java/org/mariadb/r2dbc/api/MariadbOutParameters.java +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2020-2024 MariaDB Corporation Ab - -package org.mariadb.r2dbc.api; - -import io.r2dbc.spi.OutParameters; -import io.r2dbc.spi.RowMetadata; -import org.mariadb.r2dbc.client.MariadbOutParametersMetadata; - -/** A {@link io.r2dbc.spi.OutParameters} for a MariaDB/MySQL database. */ -public interface MariadbOutParameters extends OutParameters { - - /** - * Returns the {@link RowMetadata} for all columns in this row. - * - * @return the {@link RowMetadata} for all columns in this row - * @since 0.9 - */ - MariadbOutParametersMetadata getMetadata(); -} diff --git a/src/main/java/org/mariadb/r2dbc/api/MariadbOutSegment.java b/src/main/java/org/mariadb/r2dbc/api/MariadbOutSegment.java deleted file mode 100644 index b3e3d09e..00000000 --- a/src/main/java/org/mariadb/r2dbc/api/MariadbOutSegment.java +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2020-2024 MariaDB Corporation Ab - -package org.mariadb.r2dbc.api; - -import io.r2dbc.spi.Result; -import io.r2dbc.spi.Row; - -public interface MariadbOutSegment extends Result.OutSegment { - Row row(); -} diff --git a/src/main/java/org/mariadb/r2dbc/client/DecoderState.java b/src/main/java/org/mariadb/r2dbc/client/DecoderState.java index 2f8275dc..66cf1134 100644 --- a/src/main/java/org/mariadb/r2dbc/client/DecoderState.java +++ b/src/main/java/org/mariadb/r2dbc/client/DecoderState.java @@ -123,18 +123,11 @@ public DecoderState next(MariadbFrameDecoder decoder) { EOF_INTERMEDIATE_RESPONSE { @Override public ServerMessage decode(ByteBuf body, Sequencer sequencer, MariadbFrameDecoder decoder) { - EofPacket eof = EofPacket.decode(body, decoder.getContext(), false); - decoder.setStateCounter((eof.getServerStatus() & ServerStatus.PS_OUT_PARAMETERS) > 0 ? 1 : 0); - return eof; + return EofPacket.decode(body, decoder.getContext(), false); } @Override public DecoderState next(MariadbFrameDecoder decoder) { - // mysql has a broken protocol for output parameter, then driver need to know state - if (decoder.getStateCounter() > 0) { - decoder.setStateCounter(0); - return ROW_RESPONSE_OUT_PARAM; - } return ROW_RESPONSE; } }, @@ -185,25 +178,6 @@ public DecoderState decoder(short val, int len) { } }, - ROW_RESPONSE_OUT_PARAM { - @Override - public DecoderState decoder(short val, int len) { - switch (val) { - case 254: - if (len < 0xffffff) { - return EOF_END_OUT_PARAM; - } else { - // normal ROW - return ROW_OUTPUT_PARAM; - } - case 255: // 0xFF - return ERROR; - default: - return ROW_OUTPUT_PARAM; - } - } - }, - ROW { @Override public ServerMessage decode(ByteBuf body, Sequencer sequencer, MariadbFrameDecoder decoder) { @@ -216,18 +190,6 @@ public DecoderState next(MariadbFrameDecoder decoder) { } }, - ROW_OUTPUT_PARAM { - @Override - public ServerMessage decode(ByteBuf body, Sequencer sequencer, MariadbFrameDecoder decoder) { - return new RowPacket(body); - } - - @Override - public DecoderState next(MariadbFrameDecoder decoder) { - return ROW_RESPONSE_OUT_PARAM; - } - }, - PREPARE_RESPONSE { @Override public DecoderState decoder(short val, int len) { diff --git a/src/main/java/org/mariadb/r2dbc/client/MariadbOutParameters.java b/src/main/java/org/mariadb/r2dbc/client/MariadbOutParameters.java deleted file mode 100644 index 7b3381e1..00000000 --- a/src/main/java/org/mariadb/r2dbc/client/MariadbOutParameters.java +++ /dev/null @@ -1,202 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2020-2024 MariaDB Corporation Ab - -package org.mariadb.r2dbc.client; - -import io.netty.buffer.ByteBuf; -import io.r2dbc.spi.R2dbcTransientResourceException; -import org.mariadb.r2dbc.ExceptionFactory; -import org.mariadb.r2dbc.codec.Codec; -import org.mariadb.r2dbc.codec.Codecs; -import org.mariadb.r2dbc.message.server.ColumnDefinitionPacket; -import org.mariadb.r2dbc.util.Assert; -import reactor.util.annotation.Nullable; - -public class MariadbOutParameters implements org.mariadb.r2dbc.api.MariadbOutParameters { - protected static final int NULL_LENGTH = -1; - protected final MariadbOutParametersMetadata meta; - protected final ByteBuf buf; - protected final ExceptionFactory factory; - private final int columnNumber; - private final byte[] nullBitmap; - protected int length; - protected int index = -1; - - public MariadbOutParameters( - ByteBuf buf, MariadbOutParametersMetadata meta, ExceptionFactory factory) { - this.buf = buf; - this.meta = meta; - this.factory = factory; - columnNumber = meta.getParameterMetadatas().size(); - nullBitmap = new byte[(columnNumber + 9) / 8]; - buf.skipBytes(1); // skip 0x00 header - buf.readBytes(nullBitmap); - buf.markReaderIndex(); - } - - @Nullable - @Override - @SuppressWarnings("unchecked") - public T get(int index, Class type) { - - // check NULL-Bitmap that indicate if field is null - if ((nullBitmap[(index + 2) / 8] & (1 << ((index + 2) % 8))) != 0) { - if (type != null && type.isPrimitive()) { - throw new R2dbcTransientResourceException( - String.format("Cannot return null for primitive %s", type.getName())); - } - return null; - } - - ColumnDefinitionPacket column = meta.getParameterMetadata(index); - this.setPosition(index); - if (length == NULL_LENGTH) { - if (type.isPrimitive()) { - throw new R2dbcTransientResourceException( - String.format("Cannot return null for primitive %s", type.getName())); - } - return null; - } - - // type generic, return "natural" java type - if (Object.class == type || type == null) { - Codec defaultCodec = ((Codec) column.getType().getDefaultCodec()); - return defaultCodec.decodeBinary(buf, length, column, type, factory); - } - - for (Codec codec : Codecs.LIST) { - if (codec.canDecode(column, type)) { - return ((Codec) codec).decodeBinary(buf, length, column, type, factory); - } - } - - buf.skipBytes(length); - - throw MariadbRow.noDecoderException(column, type); - } - - @Nullable - @Override - public T get(String name, Class type) { - Assert.requireNonNull(name, "name must not be null"); - return get(this.meta.getIndex(name), type); - } - - /** - * Set length and pos indicator to asked index. - * - * @param newIndex index (0 is first). - */ - public void setPosition(int newIndex) { - - if (index >= newIndex) { - index = 0; - buf.resetReaderIndex(); - } else { - index++; - } - - for (; index < newIndex; index++) { - if ((nullBitmap[(index + 2) / 8] & (1 << ((index + 2) % 8))) == 0) { - // skip bytes - switch (meta.getParameterMetadata(index).getDataType()) { - case BIGINT: - case DOUBLE: - buf.skipBytes(8); - break; - - case INTEGER: - case MEDIUMINT: - case FLOAT: - buf.skipBytes(4); - break; - - case SMALLINT: - case YEAR: - buf.skipBytes(2); - break; - - case TINYINT: - buf.skipBytes(1); - break; - - default: - int type = this.buf.readUnsignedByte(); - switch (type) { - case 251: - break; - - case 252: - this.buf.skipBytes(this.buf.readUnsignedShortLE()); - break; - - case 253: - this.buf.skipBytes(this.buf.readUnsignedMediumLE()); - break; - - case 254: - this.buf.skipBytes((int) this.buf.readLongLE()); - break; - - default: - this.buf.skipBytes(type); - break; - } - break; - } - } - } - - // read asked field position and length - switch (meta.getParameterMetadata(index).getDataType()) { - case BIGINT: - case DOUBLE: - length = 8; - return; - - case INTEGER: - case MEDIUMINT: - case FLOAT: - length = 4; - return; - - case SMALLINT: - case YEAR: - length = 2; - return; - - case TINYINT: - length = 1; - return; - - default: - // field with variable length - int len = this.buf.readUnsignedByte(); - switch (len) { - case 252: - // length is encoded on 3 bytes (0xfc header + 2 bytes indicating length) - length = this.buf.readUnsignedShortLE(); - return; - - case 253: - // length is encoded on 4 bytes (0xfd header + 3 bytes indicating length) - length = this.buf.readUnsignedMediumLE(); - return; - - case 254: - // length is encoded on 9 bytes (0xfe header + 8 bytes indicating length) - length = (int) this.buf.readLongLE(); - return; - - default: - // length is encoded on 1 byte (is then less than 251) - length = len; - } - } - } - - @Override - public MariadbOutParametersMetadata getMetadata() { - return meta; - } -} diff --git a/src/main/java/org/mariadb/r2dbc/client/MariadbOutParametersMetadata.java b/src/main/java/org/mariadb/r2dbc/client/MariadbOutParametersMetadata.java deleted file mode 100644 index 39295124..00000000 --- a/src/main/java/org/mariadb/r2dbc/client/MariadbOutParametersMetadata.java +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// Copyright (c) 2020-2024 MariaDB Corporation Ab - -package org.mariadb.r2dbc.client; - -import io.r2dbc.spi.OutParameterMetadata; -import io.r2dbc.spi.OutParametersMetadata; -import java.util.*; -import org.mariadb.r2dbc.message.server.ColumnDefinitionPacket; -import org.mariadb.r2dbc.util.Assert; - -public final class MariadbOutParametersMetadata implements OutParametersMetadata { - - private final List metadataList; - private volatile Collection columnNames; - private Map mapper = null; - - MariadbOutParametersMetadata(List metadataList) { - this.metadataList = metadataList; - } - - @Override - public ColumnDefinitionPacket getParameterMetadata(int index) { - if (index < 0 || index >= this.metadataList.size()) { - throw new IllegalArgumentException( - String.format( - "Column index %d is not in permit range[0,%s]", index, this.metadataList.size() - 1)); - } - return this.metadataList.get(index); - } - - @Override - public ColumnDefinitionPacket getParameterMetadata(String name) { - return metadataList.get(getIndex(name)); - } - - @Override - public List getParameterMetadatas() { - return Collections.unmodifiableList(this.metadataList); - } - - int getIndex(String name) throws NoSuchElementException { - Assert.requireNonNull(name, "name must not be null"); - - if (mapper == null) { - Map tmpmapper = new HashMap<>(); - for (int i = 0; i < metadataList.size(); i++) { - ColumnDefinitionPacket ci = metadataList.get(i); - String columnAlias = ci.getName(); - if (columnAlias == null || columnAlias.isEmpty()) { - String columnName = ci.getColumn(); - if (columnName != null && !columnName.isEmpty()) { - columnName = columnName.toLowerCase(Locale.ROOT); - tmpmapper.putIfAbsent(columnName, i); - } - } else { - tmpmapper.putIfAbsent(columnAlias.toLowerCase(Locale.ROOT), i); - } - } - mapper = tmpmapper; - } - - Integer ind = mapper.get(name.toLowerCase(Locale.ROOT)); - if (ind == null) { - throw new NoSuchElementException( - String.format( - "Column name '%s' does not exist in column names %s", - name, Collections.unmodifiableCollection(mapper.keySet()))); - } - return ind; - } -} diff --git a/src/main/java/org/mariadb/r2dbc/client/MariadbSegmentResult.java b/src/main/java/org/mariadb/r2dbc/client/MariadbSegmentResult.java index 1fb3c367..53a62165 100644 --- a/src/main/java/org/mariadb/r2dbc/client/MariadbSegmentResult.java +++ b/src/main/java/org/mariadb/r2dbc/client/MariadbSegmentResult.java @@ -51,7 +51,6 @@ private MariadbSegmentResult(Flux segments) { final AtomicReference rowConstructor = new AtomicReference<>(); final AtomicReference meta = new AtomicReference<>(); - final AtomicBoolean isOutputParameter = new AtomicBoolean(); this.segments = messages.handle( (message, sink) -> { @@ -87,9 +86,6 @@ private MariadbSegmentResult(Flux segments) { if (prepareResult != null && prepareResult.get() != null && metaFollows.get()) { prepareResult.get().setColumns(columnsArray); } - - isOutputParameter.set( - (eof.getServerStatus() & ServerStatus.PS_OUT_PARAMETERS) > 0); } return; } @@ -133,16 +129,9 @@ private MariadbSegmentResult(Flux segments) { if (message instanceof RowPacket) { RowPacket row = ((RowPacket) message); - if (isOutputParameter.get()) { - org.mariadb.r2dbc.api.MariadbOutParameters outParameters = - new MariadbOutParameters( - row.getRaw(), new MariadbOutParametersMetadata(columns), factory); - sink.next(new MariadbOutSegment(outParameters, (RowPacket) message)); - } else { - org.mariadb.r2dbc.api.MariadbRow rowSegment = - rowConstructor.get().create(row.getRaw(), meta.get(), factory); - sink.next(new MariadbRowSegment(rowSegment, (RowPacket) message)); - } + org.mariadb.r2dbc.api.MariadbRow rowSegment = + rowConstructor.get().create(row.getRaw(), meta.get(), factory); + sink.next(new MariadbRowSegment(rowSegment, (RowPacket) message)); } }); } @@ -292,33 +281,6 @@ public ReferenceCounted touch(Object hint) { } } - static class MariadbOutSegment extends AbstractReferenceCounted implements Result.OutSegment { - - private final OutParameters outParameters; - - private final ReferenceCounted releaseable; - - public MariadbOutSegment(OutParameters outParameters, ReferenceCounted releaseable) { - this.outParameters = outParameters; - this.releaseable = releaseable; - } - - @Override - public OutParameters outParameters() { - return outParameters; - } - - @Override - protected void deallocate() { - ReferenceCountUtil.release(this.releaseable); - } - - @Override - public ReferenceCounted touch(Object hint) { - return this; - } - } - static class MariadbUpdateCountSegment implements Result.UpdateCount { private final long value; diff --git a/src/main/java/org/mariadb/r2dbc/message/server/ColumnDefinitionPacket.java b/src/main/java/org/mariadb/r2dbc/message/server/ColumnDefinitionPacket.java index 0a0ad218..7a8da5fd 100644 --- a/src/main/java/org/mariadb/r2dbc/message/server/ColumnDefinitionPacket.java +++ b/src/main/java/org/mariadb/r2dbc/message/server/ColumnDefinitionPacket.java @@ -6,7 +6,6 @@ import io.netty.buffer.ByteBuf; import io.r2dbc.spi.ColumnMetadata; import io.r2dbc.spi.Nullability; -import io.r2dbc.spi.OutParameterMetadata; import java.nio.charset.StandardCharsets; import org.mariadb.r2dbc.MariadbConnectionConfiguration; import org.mariadb.r2dbc.codec.DataType; @@ -16,7 +15,7 @@ import org.mariadb.r2dbc.util.constants.ColumnFlags; public final class ColumnDefinitionPacket - implements ServerMessage, ColumnMetadata, OutParameterMetadata { + implements ServerMessage, ColumnMetadata { private final byte[] meta; private final int charset; private final long length; diff --git a/src/test/java/org/mariadb/r2dbc/integration/ProcedureResultsetTest.java b/src/test/java/org/mariadb/r2dbc/integration/ProcedureResultsetTest.java index ab4e2d83..dad1697d 100644 --- a/src/test/java/org/mariadb/r2dbc/integration/ProcedureResultsetTest.java +++ b/src/test/java/org/mariadb/r2dbc/integration/ProcedureResultsetTest.java @@ -3,16 +3,8 @@ package org.mariadb.r2dbc.integration; -import io.r2dbc.spi.OutParametersMetadata; -import io.r2dbc.spi.Parameters; -import io.r2dbc.spi.R2dbcType; -import io.r2dbc.spi.Result; -import java.time.LocalDateTime; -import java.util.List; -import java.util.NoSuchElementException; import org.junit.jupiter.api.*; import org.mariadb.r2dbc.BaseConnectionTest; -import reactor.core.publisher.Flux; import reactor.test.StepVerifier; public class ProcedureResultsetTest extends BaseConnectionTest { @@ -50,102 +42,6 @@ public static void dropAll() { sharedConn.createStatement("DROP PROCEDURE IF EXISTS no_out_proc").execute().blockLast(); } - @Test - @Disabled // TODO: PLAT-7673 - void outputParameter() { - // https://jira.mariadb.org/browse/XPT-268 - Assumptions.assumeFalse(isXpand()); - List> l = - sharedConn - .createStatement("call basic_proc(?,?,?,?,?,?,?)") - .bind(0, 2) - .bind(1, Parameters.inOut(2)) - .bind(2, Parameters.out(R2dbcType.INTEGER)) - .bind(3, 10) - .bind(4, Parameters.out(R2dbcType.VARCHAR)) - .bind(5, Parameters.out(R2dbcType.TIMESTAMP)) - .bind(6, Parameters.out(R2dbcType.VARCHAR)) - .execute() - .flatMap( - r -> - Flux.from( - r.filter(Result.OutSegment.class::isInstance) - .flatMap( - seg -> { - OutParametersMetadata metas = - ((Result.OutSegment) seg).outParameters().getMetadata(); - - assertThrows( - IllegalArgumentException.class, - () -> metas.getParameterMetadata(-1), - "Column index -1 is not in permit range[0,4]"); - assertThrows( - IllegalArgumentException.class, - () -> metas.getParameterMetadata(10), - "Column index 10 is not in permit range[0,4]"); - - Assertions.assertEquals( - metas.getParameterMetadata(0), - metas.getParameterMetadata("t2")); - Assertions.assertEquals( - 5, metas.getParameterMetadatas().size()); - assertThrows( - NoSuchElementException.class, - () -> metas.getParameterMetadata("wrong"), - "Column name 'wrong' does not exist in column names ["); - return Flux.just( - ((Result.OutSegment) seg).outParameters().get(0), - ((Result.OutSegment) seg).outParameters().get(1), - ((Result.OutSegment) seg).outParameters().get(2), - ((Result.OutSegment) seg).outParameters().get(3), - ((Result.OutSegment) seg).outParameters().get(4)); - })) - .collectList()) - .collectList() - .block(); - - Assertions.assertEquals(2, l.size()); - Assertions.assertEquals(0, l.get(0).size()); - Assertions.assertEquals(5, l.get(1).size()); - Assertions.assertEquals(4L, l.get(1).get(0)); - Assertions.assertEquals(20, l.get(1).get(1)); - if (isMariaDBServer() && minVersion(10, 3, 0)) { - Assertions.assertEquals("http://test", l.get(1).get(2)); - Assertions.assertEquals("test", l.get(1).get(4)); - } - Assertions.assertEquals(LocalDateTime.parse("2003-12-31T12:00:00"), l.get(1).get(3)); - - List> l2 = - sharedConn - .createStatement("/*text*/ call basic_proc(?,?,?,?,?,?,?)") - .bind(0, 2) - .bind(1, Parameters.inOut(2)) - .bind(2, Parameters.out(R2dbcType.INTEGER)) - .bind(3, 10) - .bind(4, Parameters.out(R2dbcType.VARCHAR)) - .bind(5, Parameters.out(R2dbcType.TIMESTAMP)) - .bind(6, Parameters.out(R2dbcType.VARCHAR)) - .execute() - .flatMap( - r -> - Flux.from( - r.filter(Result.OutSegment.class::isInstance) - .flatMap( - seg -> { - return Flux.just( - ((Result.OutSegment) seg).outParameters().get(0), - ((Result.OutSegment) seg).outParameters().get(1), - ((Result.OutSegment) seg).outParameters().get(2), - ((Result.OutSegment) seg).outParameters().get(3), - ((Result.OutSegment) seg).outParameters().get(4)); - })) - .collectList()) - .collectList() - .block(); - - Assertions.assertEquals(1, l2.size()); - } - @Test void inParameter() { Assumptions.assumeFalse(isXpand());