Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions lang/csharp/src/apache/main/AvroDecimal.cs
Original file line number Diff line number Diff line change
Expand Up @@ -917,7 +917,7 @@ TypeCode IConvertible.GetTypeCode()
/// </returns>
bool IConvertible.ToBoolean(IFormatProvider provider)
{
return Convert.ToBoolean(this, provider);
return (bool)((IConvertible)this).ToType(typeof(bool), provider);
}

/// <summary>
Expand All @@ -929,7 +929,7 @@ bool IConvertible.ToBoolean(IFormatProvider provider)
/// </returns>
byte IConvertible.ToByte(IFormatProvider provider)
{
return Convert.ToByte(this, provider);
return (byte)((IConvertible)this).ToType(typeof(byte), provider);
}

/// <summary>
Expand Down Expand Up @@ -967,7 +967,7 @@ DateTime IConvertible.ToDateTime(IFormatProvider provider)
/// </returns>
decimal IConvertible.ToDecimal(IFormatProvider provider)
{
return Convert.ToDecimal(this, provider);
return (decimal)((IConvertible)this).ToType(typeof(decimal), provider);
}

/// <summary>
Expand All @@ -979,7 +979,7 @@ decimal IConvertible.ToDecimal(IFormatProvider provider)
/// </returns>
double IConvertible.ToDouble(IFormatProvider provider)
{
return Convert.ToDouble(this, provider);
return (double)((IConvertible)this).ToType(typeof(double), provider);
}

/// <summary>
Expand All @@ -991,7 +991,7 @@ double IConvertible.ToDouble(IFormatProvider provider)
/// </returns>
short IConvertible.ToInt16(IFormatProvider provider)
{
return Convert.ToInt16(this, provider);
return (short)((IConvertible)this).ToType(typeof(short), provider);
}

/// <summary>
Expand All @@ -1003,7 +1003,7 @@ short IConvertible.ToInt16(IFormatProvider provider)
/// </returns>
int IConvertible.ToInt32(IFormatProvider provider)
{
return Convert.ToInt32(this, provider);
return (int)((IConvertible)this).ToType(typeof(int), provider);
}

/// <summary>
Expand All @@ -1015,7 +1015,7 @@ int IConvertible.ToInt32(IFormatProvider provider)
/// </returns>
long IConvertible.ToInt64(IFormatProvider provider)
{
return Convert.ToInt64(this, provider);
return (long)((IConvertible)this).ToType(typeof(long), provider);
}

/// <summary>
Expand All @@ -1027,7 +1027,7 @@ long IConvertible.ToInt64(IFormatProvider provider)
/// </returns>
sbyte IConvertible.ToSByte(IFormatProvider provider)
{
return Convert.ToSByte(this, provider);
return (sbyte)((IConvertible)this).ToType(typeof(sbyte), provider);
}

/// <summary>
Expand All @@ -1039,7 +1039,7 @@ sbyte IConvertible.ToSByte(IFormatProvider provider)
/// </returns>
float IConvertible.ToSingle(IFormatProvider provider)
{
return Convert.ToSingle(this, provider);
return (float)((IConvertible)this).ToType(typeof(float), provider);
}

/// <summary>
Expand All @@ -1051,7 +1051,7 @@ float IConvertible.ToSingle(IFormatProvider provider)
/// </returns>
string IConvertible.ToString(IFormatProvider provider)
{
return Convert.ToString(this, provider);
return ToString();
}

/// <summary>
Expand All @@ -1063,7 +1063,7 @@ string IConvertible.ToString(IFormatProvider provider)
/// </returns>
ushort IConvertible.ToUInt16(IFormatProvider provider)
{
return Convert.ToUInt16(this, provider);
return (ushort)((IConvertible)this).ToType(typeof(ushort), provider);
}

/// <summary>
Expand All @@ -1075,7 +1075,7 @@ ushort IConvertible.ToUInt16(IFormatProvider provider)
/// </returns>
uint IConvertible.ToUInt32(IFormatProvider provider)
{
return Convert.ToUInt32(this, provider);
return (uint)((IConvertible)this).ToType(typeof(uint), provider);
}

/// <summary>
Expand All @@ -1087,7 +1087,7 @@ uint IConvertible.ToUInt32(IFormatProvider provider)
/// </returns>
ulong IConvertible.ToUInt64(IFormatProvider provider)
{
return Convert.ToUInt64(this, provider);
return (ulong)((IConvertible)this).ToType(typeof(ulong), provider);
}

/// <summary>
Expand Down
24 changes: 24 additions & 0 deletions lang/csharp/src/apache/test/AvroDecimalTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* limitations under the License.
*/

using System;
using System.Globalization;
using NUnit.Framework;

Expand Down Expand Up @@ -91,5 +92,28 @@ public int TestAvroDecimalCompareTo(string left, string right)

return leftAvroDecimal.CompareTo(rightAvroDecimal);
}

// AVRO-3569: the IConvertible conversions previously called
// Convert.ToXxx(this, provider), which recurses back into the same
// IConvertible method and overflows the stack. Verify they now return
// the converted value instead of crashing.
[Test]
public void TestAvroDecimalIConvertibleDoesNotRecurse()
{
var d = new AvroDecimal(42);
Assert.AreEqual((byte)42, Convert.ToByte(d));
Assert.AreEqual((sbyte)42, Convert.ToSByte(d));
Assert.AreEqual((short)42, Convert.ToInt16(d));
Assert.AreEqual(42, Convert.ToInt32(d));
Assert.AreEqual(42L, Convert.ToInt64(d));
Assert.AreEqual((ushort)42, Convert.ToUInt16(d));
Assert.AreEqual(42u, Convert.ToUInt32(d));
Assert.AreEqual(42ul, Convert.ToUInt64(d));
Assert.AreEqual(42d, Convert.ToDouble(d));
Assert.AreEqual(42f, Convert.ToSingle(d));
Assert.AreEqual(42m, Convert.ToDecimal(d));
Assert.AreEqual(true, Convert.ToBoolean(d));
Assert.AreEqual("42", Convert.ToString(d, CultureInfo.InvariantCulture));
}
}
}
43 changes: 43 additions & 0 deletions lang/java/avro/src/test/java/org/apache/avro/TestResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,13 @@

import org.apache.avro.data.TimeConversions;
import org.apache.avro.generic.IndexedRecord;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericDatumReader;
import org.apache.avro.generic.GenericDatumWriter;
import org.apache.avro.generic.GenericRecord;
import org.apache.avro.io.DatumReader;
import org.apache.avro.io.DecoderFactory;
import org.apache.avro.io.EncoderFactory;
import org.apache.avro.io.FastReaderBuilder;
import org.apache.avro.io.JsonDecoder;
import org.hamcrest.MatcherAssert;
Expand Down Expand Up @@ -103,6 +108,44 @@ void resolveEnum() throws IOException {
Assertions.assertEquals("e3", result.get(0).toString());
}

// AVRO-3235: enums (and their enclosing records) that share the same simple
// name but live in different namespaces must still resolve, so that data
// versioned by namespace stays backward/forward compatible.
@Test
void resolveEnumAcrossNamespaces() throws IOException {
final Schema writeEnum = Schema.createEnum("Status", "", "test.v1", Arrays.asList("ON", "OFF"));
final Schema readEnum = Schema.createEnum("Status", "", "test.v2", Arrays.asList("ON", "OFF"));

// The enum action must be an EnumAdjust, not a NAMES_DONT_MATCH error.
Resolver.Action enumAction = Resolver.resolve(writeEnum, readEnum);
MatcherAssert.assertThat(enumAction, Matchers.instanceOf(Resolver.EnumAdjust.class));

// Full record round-trip: writer record in v1, reader record in v2 with an
// extra defaulted field; the enum resolves and the default is inserted.
Schema writeRecord = Schema.createRecord("Simple", "", "test.v1", false,
Arrays.asList(new Schema.Field("name", Schema.create(Schema.Type.STRING), ""),
new Schema.Field("status", writeEnum, "", "ON")));
Schema readRecord = Schema.createRecord("Simple", "", "test.v2", false,
Arrays.asList(new Schema.Field("name", Schema.create(Schema.Type.STRING), ""),
new Schema.Field("description", Schema.create(Schema.Type.STRING), "", ""),
new Schema.Field("status", readEnum, "", "ON")));

GenericData.Record rec = new GenericData.Record(writeRecord);
rec.put("name", "A");
rec.put("status", new GenericData.EnumSymbol(writeEnum, "ON"));
java.io.ByteArrayOutputStream bos = new java.io.ByteArrayOutputStream();
org.apache.avro.io.Encoder enc = EncoderFactory.get().binaryEncoder(bos, null);
new GenericDatumWriter<GenericRecord>(writeRecord).write(rec, enc);
enc.flush();

GenericDatumReader<GenericRecord> datumReader = new GenericDatumReader<>(writeRecord, readRecord);
GenericRecord out = datumReader.read(null,
DecoderFactory.get().binaryDecoder(bos.toByteArray(), null));
Assertions.assertEquals("A", out.get("name").toString());
Assertions.assertEquals("", out.get("description").toString());
Assertions.assertEquals("ON", out.get("status").toString());
}

@Test
void promoteIsValid() {
Assertions.assertThrows(IllegalArgumentException.class,
Expand Down
Loading