flink-issues mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From GitBox <...@apache.org>
Subject [GitHub] [flink] twalthr commented on a change in pull request #8360: [FLINK-12393][table-common] Add the user-facing classes of the new type system
Date Thu, 09 May 2019 06:02:42 GMT
twalthr commented on a change in pull request #8360: [FLINK-12393][table-common] Add the user-facing
classes of the new type system
URL: https://github.com/apache/flink/pull/8360#discussion_r282348005
 
 

 ##########
 File path: flink-table/flink-table-common/src/main/java/org/apache/flink/table/api/DataTypes.java
 ##########
 @@ -0,0 +1,703 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.flink.table.api;
+
+import org.apache.flink.annotation.PublicEvolving;
+import org.apache.flink.api.common.ExecutionConfig;
+import org.apache.flink.api.common.typeinfo.TypeInformation;
+import org.apache.flink.api.common.typeutils.TypeSerializer;
+import org.apache.flink.table.types.DataType;
+import org.apache.flink.table.types.logical.AnyType;
+import org.apache.flink.table.types.logical.ArrayType;
+import org.apache.flink.table.types.logical.BigIntType;
+import org.apache.flink.table.types.logical.BinaryType;
+import org.apache.flink.table.types.logical.BooleanType;
+import org.apache.flink.table.types.logical.CharType;
+import org.apache.flink.table.types.logical.DateType;
+import org.apache.flink.table.types.logical.DayTimeIntervalType;
+import org.apache.flink.table.types.logical.DayTimeIntervalType.DayTimeResolution;
+import org.apache.flink.table.types.logical.DecimalType;
+import org.apache.flink.table.types.logical.DoubleType;
+import org.apache.flink.table.types.logical.FloatType;
+import org.apache.flink.table.types.logical.IntType;
+import org.apache.flink.table.types.logical.LocalZonedTimestampType;
+import org.apache.flink.table.types.logical.LogicalType;
+import org.apache.flink.table.types.logical.MapType;
+import org.apache.flink.table.types.logical.MultisetType;
+import org.apache.flink.table.types.logical.NullType;
+import org.apache.flink.table.types.logical.RowType;
+import org.apache.flink.table.types.logical.SmallIntType;
+import org.apache.flink.table.types.logical.TimeType;
+import org.apache.flink.table.types.logical.TimestampType;
+import org.apache.flink.table.types.logical.TinyIntType;
+import org.apache.flink.table.types.logical.TypeInformationAnyType;
+import org.apache.flink.table.types.logical.VarBinaryType;
+import org.apache.flink.table.types.logical.VarCharType;
+import org.apache.flink.table.types.logical.YearMonthIntervalType;
+import org.apache.flink.table.types.logical.YearMonthIntervalType.YearMonthResolution;
+import org.apache.flink.table.types.logical.ZonedTimestampType;
+import org.apache.flink.util.Preconditions;
+
+import javax.annotation.Nullable;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.function.BiFunction;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * A {@link DataType} can be used to declare input and/or output types of operations. This
class
+ * enumerates all supported data types of the Table & SQL API.
+ */
+@PublicEvolving
+public final class DataTypes {
+
+	// we use SQL-like naming for data types and avoid Java keyword clashes
+	// CHECKSTYLE.OFF: MethodName
+
+	/**
+	 * Data type of a fixed-length character string {@code CHAR(n)} where {@code n} is the number
+	 * of code points. {@code n} must have a value between 1 and 255 (both inclusive).
+	 *
+	 * @see CharType
+	 */
+	public static DataType.AtomicDataType CHAR(int n) {
+		return new DataType.AtomicDataType(new CharType(n));
+	}
+
+	/**
+	 * Data type of a variable-length character string {@code VARCHAR(n)} where {@code n} is
the
+	 * maximum number of code points. {@code n} must have a value between 1 and {@link Integer#MAX_VALUE}
+	 * (both inclusive).
+	 *
+	 * @see VarCharType
+	 */
+	public static DataType.AtomicDataType VARCHAR(int n) {
+		return new DataType.AtomicDataType(new VarCharType(n));
+	}
+
+	/**
+	 * Data type of a variable-length character string with defined maximum length. This is
a shortcut
+	 * for {@code VARCHAR(2147483647)} for representing JVM strings.
+	 *
+	 * @see VarCharType
+	 */
+	public static DataType.AtomicDataType STRING() {
+		return VARCHAR(Integer.MAX_VALUE);
+	}
+
+	/**
+	 * Data type of a boolean with a (possibly) three-valued logic of {@code TRUE, FALSE, UNKNOWN}.
+	 *
+	 * @see BooleanType
+	 */
+	public static DataType.AtomicDataType BOOLEAN() {
+		return new DataType.AtomicDataType(new BooleanType());
+	}
+
+	/**
+	 * Data type of a fixed-length binary string (=a sequence of bytes) {@code BINARY(n)} where
+	 * {@code n} is the number of bytes. {@code n} must have a value between 1 and {@link Integer#MAX_VALUE}
+	 * (both inclusive).
+	 *
+	 * @see BinaryType
+	 */
+	public static DataType.AtomicDataType BINARY(int n) {
+		return new DataType.AtomicDataType(new BinaryType(n));
+	}
+
+	/**
+	 * Data type of a variable-length binary string (=a sequence of bytes) {@code VARBINARY(n)}
where
+	 * {@code n} is the maximum number of bytes. {@code n} must have a value between 1 and {@link
Integer#MAX_VALUE}
+	 * (both inclusive).
+	 *
+	 * @see VarBinaryType
+	 */
+	public static DataType.AtomicDataType VARBINARY(int n) {
+		return new DataType.AtomicDataType(new VarBinaryType(n));
+	}
+
+	/**
+	 * Data type of a variable-length binary string (=a sequence of bytes) with defined maximum
length.
+	 * This is a shortcut for {@code VARBINARY(2147483647)} for representing JVM byte arrays.
+	 *
+	 * @see VarBinaryType
+	 */
+	public static DataType.AtomicDataType BYTES() {
+		return VARBINARY(Integer.MAX_VALUE);
+	}
+
+	/**
+	 * Data type of a decimal number with fixed precision and scale {@code DECIMAL(p, s)} where
{@code p}
+	 * is the number of digits in a number (=precision) and {@code s} is the number of digits
to the
+	 * right of the decimal point in a number (=scale). {@code p} must have a value between
1 and 38
+	 * (both inclusive). {@code s} must have a value between 0 and {@code p} (both inclusive).
+	 *
+	 * @see DecimalType
+	 */
+	public static DataType.AtomicDataType DECIMAL(int precision, int scale) {
+		return new DataType.AtomicDataType(new DecimalType(precision, scale));
+	}
+
+	/**
+	 * Data type of a 1-byte signed integer with values from -128 to 127.
+	 *
+	 * @see TinyIntType
+	 */
+	public static DataType.AtomicDataType TINYINT() {
+		return new DataType.AtomicDataType(new TinyIntType());
+	}
+
+	/**
+	 * Data type of a 2-byte signed integer with values from -32,768 to 32,767.
+	 *
+	 * @see SmallIntType
+	 */
+	public static DataType.AtomicDataType SMALLINT() {
+		return new DataType.AtomicDataType(new SmallIntType());
+	}
+
+	/**
+	 * Data type of a 4-byte signed integer with values from -2,147,483,648 to 2,147,483,647.
+	 *
+	 * @see IntType
+	 */
+	public static DataType.AtomicDataType INT() {
+		return new DataType.AtomicDataType(new IntType());
+	}
+
+	/**
+	 * Data type of an 8-byte signed integer with values from -9,223,372,036,854,775,808 to
+	 * 9,223,372,036,854,775,807.
+	 *
+	 * @see BigIntType
+	 */
+	public static DataType.AtomicDataType BIGINT() {
+		return new DataType.AtomicDataType(new BigIntType());
+	}
+
+	/**
+	 * Data type of a 4-byte single precision floating point number.
+	 *
+	 * @see FloatType
+	 */
+	public static DataType.AtomicDataType FLOAT() {
+		return new DataType.AtomicDataType(new FloatType());
+	}
+
+	/**
+	 * Data type of an 8-byte double precision floating point number.
+	 *
+	 * @see DoubleType
+	 */
+	public static DataType.AtomicDataType DOUBLE() {
+		return new DataType.AtomicDataType(new DoubleType());
+	}
+
+	/**
+	 * Data type of a date consisting of {@code year-month-day} with values ranging from {@code
0000-01-01}
+	 * to {@code 9999-12-31}.
+	 *
+	 * <p>Compared to the SQL standard, the range starts at year {@code 0000}.
+	 *
+	 * @see DataType
+	 */
+	public static DataType.AtomicDataType DATE() {
+		return new DataType.AtomicDataType(new DateType());
+	}
+
+	/**
+	 * Data type of a time WITHOUT time zone {@code TIME(p)} where {@code p} is the number of
digits
+	 * of fractional seconds (=precision). {@code p} must have a value between 0 and 9 (both
inclusive).
+	 *
+	 * <p>An instance consists of {@code hour:minute:second[.fractional]} with up to nanosecond
precision
+	 * and values ranging from {@code 00:00:00.000000000} to {@code 23:59:59.999999999}.
+	 *
+	 * <p>Compared to the SQL standard, leap seconds (23:59:60 and 23:59:61) are not supported
as the
+	 * semantics are closer to {@link java.time.LocalTime}. A time WITH time zone is not provided.
+	 *
+	 * @see TimeType
+	 */
+	public static DataType.AtomicDataType TIME(int precision) {
+		return new DataType.AtomicDataType(new TimeType(precision));
+	}
+
+	/**
+	 * Data type of a timestamp WITHOUT time zone {@code TIMESTAMP(p)} where {@code p} is the
number
+	 * of digits of fractional seconds (=precision). {@code p} must have a value between 0 and
9 (both
+	 * inclusive).
+	 *
+	 * <p>An instance consists of {@code year-month-day hour:minute:second[.fractional]}
with up to
+	 * nanosecond precision and values ranging from {@code 0000-01-01 00:00:00.000000000} to
+	 * {@code 9999-12-31 23:59:59.999999999}.
+	 *
+	 * <p>Compared to the SQL standard, leap seconds (23:59:60 and 23:59:61) are not supported
as the
+	 * semantics are closer to {@link java.time.LocalDateTime}.
+	 *
+	 * @see #TIMESTAMP_WITH_TIME_ZONE(int)
+	 * @see #TIMESTAMP_WITH_LOCAL_TIME_ZONE(int)
+	 * @see TimestampType
+	 */
+	public static DataType.AtomicDataType TIMESTAMP(int precision) {
+		return new DataType.AtomicDataType(new TimestampType(precision));
+	}
+
+	/**
+	 * Data type of a timestamp WITH time zone {@code TIMESTAMP(p) WITH TIME ZONE} where {@code
p} is
+	 * the number of digits of fractional seconds (=precision). {@code p} must have a value
between 0
+	 * and 9 (both inclusive).
+	 *
+	 * <p>An instance consists of {@code year-month-day hour:minute:second[.fractional]
zone} with up
+	 * to nanosecond precision and values ranging from {@code 0000-01-01 00:00:00.000000000
+14:59} to
+	 * {@code 9999-12-31 23:59:59.999999999 -14:59}.
+	 *
+	 * <p>Compared to the SQL standard, leap seconds (23:59:60 and 23:59:61) are not supported
as the
+	 * semantics are closer to {@link java.time.OffsetDateTime}.
+	 *
+	 * @see #TIMESTAMP(int)
+	 * @see #TIMESTAMP_WITH_LOCAL_TIME_ZONE(int)
+	 * @see ZonedTimestampType
+	 */
+	public static DataType.AtomicDataType TIMESTAMP_WITH_TIME_ZONE(int precision) {
+		return new DataType.AtomicDataType(new ZonedTimestampType(precision));
+	}
+
+	/**
+	 * Data type of a timestamp WITH LOCAL time zone {@code TIMESTAMP(p) WITH LOCAL TIME ZONE}
where
+	 * {@code p} is the number of digits of fractional seconds (=precision). {@code p} must
have a value
+	 * between 0 and 9 (both inclusive).
+	 *
+	 * <p>An instance consists of {@code year-month-day hour:minute:second[.fractional]
zone} with up
+	 * to nanosecond precision and values ranging from {@code 0000-01-01 00:00:00.000000000
+14:59} to
+	 * {@code 9999-12-31 23:59:59.999999999 -14:59}. Leap seconds (23:59:60 and 23:59:61) are
not supported
+	 * as the semantics are closer to {@link java.time.OffsetDateTime}.
+	 *
+	 * <p>Compared to {@link ZonedTimestampType}, the time zone offset information is
not stored physically
+	 * in every datum. Instead, the type assumes {@link java.time.Instant} semantics in UTC
time zone
+	 * at the edges of the table ecosystem. Every datum is interpreted in the local time zone
configured
+	 * in the current session for computation and visualization.
+	 *
+	 * <p>This type fills the gap between time zone free and time zone mandatory timestamp
types by
+	 * allowing the interpretation of UTC timestamps according to the configured session timezone.
+	 *
+	 * @see #TIMESTAMP(int)
+	 * @see #TIMESTAMP_WITH_TIME_ZONE(int)
+	 * @see LocalZonedTimestampType
+	 */
+	public static DataType.AtomicDataType TIMESTAMP_WITH_LOCAL_TIME_ZONE(int precision) {
+		return new DataType.AtomicDataType(new LocalZonedTimestampType(precision));
+	}
+
+	/**
+	 * Data type of a temporal interval. There are two types of temporal intervals: day-time
intervals
+	 * with up to nanosecond granularity or year-month intervals with up to month granularity.
+	 *
+	 * <p>An interval of day-time consists of {@code +days hours:months:seconds.fractional}
with values
+	 * ranging from {@code -999999 23:59:59.999999999} to {@code +999999 23:59:59.999999999}.
The type
+	 * must be parameterized to one of the following resolutions: interval of days, interval
of days to
+	 * hours, interval of days to minutes, interval of days to seconds, interval of hours, interval
of
+	 * hours to minutes, interval of hours to seconds, interval of minutes, interval of minutes
to seconds,
+	 * or interval of seconds. The value representation is the same for all types of resolutions.
For
+	 * example, an interval of seconds of 70 is always represented in an interval-of-days-to-seconds
+	 * format (with default precisions): {@code +00 00:01:10.000000}).
+	 *
+	 * <p>An interval of year-month consists of {@code +years-months} with values ranging
from {@code -9999-11}
+	 * to {@code +9999-11}. The type must be parameterized to one of the following resolutions:
interval
+	 * of years, interval of years to months, or interval of months. The value representation
is the
+	 * same for all types of resolutions. For example, an interval of months of 50 is always
represented
+	 * in an interval-of-years-to-months format (with default year precision): {@code +04-02}.
+	 *
+	 * <p>Examples: {@code INTERVAL(DAY(2))} for a day-time interval or {@code INTERVAL(YEAR(4))}
for
+	 * a year-month interval.
+	 *
+	 * @see DayTimeIntervalType
+	 * @see YearMonthIntervalType
+	 */
+	public static DataType.AtomicDataType INTERVAL(Resolution resolution) {
+		Preconditions.checkNotNull(resolution, "Interval resolution must not be null.");
+		return new DataType.AtomicDataType(Resolution.resolveInterval(resolution, null));
+	}
+
+	/**
+	 * Data type of a temporal interval. There are two types of temporal intervals: day-time
intervals
+	 * with up to nanosecond granularity or year-month intervals with up to month granularity.
+	 *
+	 * <p>An interval of day-time consists of {@code +days hours:months:seconds.fractional}
with values
+	 * ranging from {@code -999999 23:59:59.999999999} to {@code +999999 23:59:59.999999999}.
The type
+	 * must be parameterized to one of the following resolutions: interval of days, interval
of days to
+	 * hours, interval of days to minutes, interval of days to seconds, interval of hours, interval
of
+	 * hours to minutes, interval of hours to seconds, interval of minutes, interval of minutes
to seconds,
+	 * or interval of seconds. The value representation is the same for all types of resolutions.
For
+	 * example, an interval of seconds of 70 is always represented in an interval-of-days-to-seconds
+	 * format (with default precisions): {@code +00 00:01:10.000000}).
+	 *
+	 * <p>An interval of year-month consists of {@code +years-months} with values ranging
from {@code -9999-11}
+	 * to {@code +9999-11}. The type must be parameterized to one of the following resolutions:
interval
+	 * of years, interval of years to months, or interval of months. The value representation
is the
+	 * same for all types of resolutions. For example, an interval of months of 50 is always
represented
+	 * in an interval-of-years-to-months format (with default year precision): {@code +04-02}.
+	 *
+	 * <p>Examples: {@code INTERVAL(DAY(2), SECOND(9))} for a day-time interval or {@code
INTERVAL(YEAR(4), MONTH())}
+	 * for a year-month interval.
+	 *
+	 * @see DayTimeIntervalType
+	 * @see YearMonthIntervalType
+	 */
+	public static DataType.AtomicDataType INTERVAL(Resolution upperResolution, Resolution lowerResolution)
{
+		Preconditions.checkNotNull(upperResolution, "Upper interval resolution must not be null.");
+		Preconditions.checkNotNull(lowerResolution, "Lower interval resolution must not be null.");
+		return new DataType.AtomicDataType(Resolution.resolveInterval(upperResolution, lowerResolution));
+	}
+
+	/**
+	 * Data type of an array of elements with same subtype.
+	 *
+	 * <p>Compared to the SQL standard, the maximum cardinality of an array cannot be
specified but
+	 * is fixed at {@link Integer#MAX_VALUE}. Also, any valid type is supported as a subtype.
+	 *
+	 * @see ArrayType
+	 */
+	public static DataType.ElementDataType ARRAY(DataType elementDataType) {
+		Preconditions.checkNotNull(elementDataType, "Element data type must not be null.");
+		return new DataType.ElementDataType(new ArrayType(elementDataType.getLogicalType()), elementDataType);
+	}
+
+	/**
+	 * Data type of a multiset (=bag). Unlike a set, it allows for multiple instances for each
of its
+	 * elements with a common subtype. Each unique value (including {@code NULL}) is mapped
to some
+	 * multiplicity.
+	 *
+	 * <p>There is no restriction of element types; it is the responsibility of the user
to ensure
+	 * uniqueness.
+	 *
+	 * @see MultisetType
+	 */
+	public static DataType.ElementDataType MULTISET(DataType elementDataType) {
+		Preconditions.checkNotNull(elementDataType, "Element data type must not be null.");
+		return new DataType.ElementDataType(new MultisetType(elementDataType.getLogicalType()),
elementDataType);
+	}
+
+	/**
+	 * Data type of an associative array that maps keys (including {@code NULL}) to values (including
+	 * {@code NULL}). A map cannot contain duplicate keys; each key can map to at most one value.
+	 *
+	 * <p>There is no restriction of key types; it is the responsibility of the user to
ensure uniqueness.
+	 * The map type is an extension to the SQL standard.
+	 *
+	 * @see MapType
+	 */
+	public static DataType.KeyValueDataType MAP(DataType keyDataType, DataType valueDataType)
{
+		Preconditions.checkNotNull(keyDataType, "Key data type must not be null.");
+		Preconditions.checkNotNull(valueDataType, "Value data type must not be null.");
+		return new DataType.KeyValueDataType(
+			new MapType(keyDataType.getLogicalType(), valueDataType.getLogicalType()),
+			keyDataType,
+			valueDataType);
+	}
+
+	/**
+	 * Data type of a sequence of fields. A field consists of a field name, field type, and
an optional
+	 * description. The most specific type of a row of a table is a row type. In this case,
each column
+	 * of the row corresponds to the field of the row type that has the same ordinal position
as the
+	 * column.
+	 *
+	 * <p>Compared to the SQL standard, an optional field description simplifies the handling
with
+	 * complex structures.
+	 *
+	 * @see RowType
+	 */
+	public static DataType.FieldsDataType ROW(Field... fields) {
+		final List<RowType.RowField> logicalFields = Stream.of(fields)
+			.map(f -> Preconditions.checkNotNull(f, "Field definition must not be null."))
+			.map(f -> new RowType.RowField(f.name, f.dataType.getLogicalType(), f.description))
+			.collect(Collectors.toList());
+		final Map<String, DataType> fieldDataTypes = Stream.of(fields)
+			.collect(Collectors.toMap(f -> f.name, f -> f.dataType));
+		return new DataType.FieldsDataType(new RowType(logicalFields), fieldDataTypes);
+	}
+
+	/**
+	 * Data type for representing untyped {@code NULL} values. A null type has no other value
except
+	 * {@code NULL}, thus, it can be cast to any nullable type similar to JVM semantics.
+	 *
+	 * <p>This type helps in representing unknown types in API calls that use a {@code
NULL} literal
+	 * as well as bridging to formats such as JSON or Avro that define such a type as well.
+	 *
+	 * <p>The null type is an extension to the SQL standard.
+	 *
+	 * @see NullType
+	 */
+	public static DataType.AtomicDataType NULL() {
+		return new DataType.AtomicDataType(new NullType());
+	}
+
+	/**
+	 * Data type of an arbitrary serialized type. This type is a black box within the table
ecosystem
+	 * and is only deserialized at the edges.
+	 *
+	 * <p>The any type is an extension to the SQL standard.
+	 *
+	 * <p>This method assumes that a {@link TypeSerializer} instance is present. Use {@link
#ANY(TypeInformation)}
+	 * for generating a serializer from Flink's core type system automatically in subsequent
layers.
+	 *
+	 * @param clazz originating value class
+	 * @param serializer type serializer
+	 *
+	 * @see AnyType
+	 */
+	public static <T> DataType.AtomicDataType ANY(Class<T> clazz, TypeSerializer<T>
serializer) {
+		return new DataType.AtomicDataType(new AnyType<>(clazz, serializer));
+	}
+
+	/**
+	 * Data type of an arbitrary serialized type backed by {@link TypeInformation}. This type
is
+	 * a black box within the table ecosystem and is only deserialized at the edges.
+	 *
+	 * <p>The any type is an extension to the SQL standard.
+	 *
+	 * <p>Compared to an {@link #ANY(Class, TypeSerializer)}, this type does not contain
a {@link TypeSerializer}
+	 * yet. The serializer will be generated from the enclosed {@link TypeInformation} but needs
access
+	 * to the {@link ExecutionConfig} of the current execution environment. Thus, this type
is just a
+	 * placeholder.
+	 *
+	 * @see TypeInformationAnyType
+	 */
+	public static <T> DataType.AtomicDataType ANY(TypeInformation<T> typeInformation)
{
+		return new DataType.AtomicDataType(new TypeInformationAnyType<>(typeInformation));
+	}
+
+	// --------------------------------------------------------------------------------------------
+	// Helper functions
+	// --------------------------------------------------------------------------------------------
+
+	/**
+	 * Resolution in seconds and (possibly) fractional seconds. The precision is the number
of
+	 * digits of fractional seconds. It must have a value between 0 and 9 (both inclusive).
If
+	 * no fractional is specified, it is equal to 6 by default.
+	 */
+	public static Resolution SECOND(int precision) {
+		return new Resolution(Resolution.IntervalUnit.SECOND, precision);
+	}
+
+	/**
+	 * Resolution in minutes.
+	 */
+	public static Resolution MINUTE() {
+		return new Resolution(Resolution.IntervalUnit.MINUTE);
+	}
+
+	/**
+	 * Resolution in hours.
+	 */
+	public static Resolution HOUR() {
+		return new Resolution(Resolution.IntervalUnit.HOUR);
+	}
+
+	/**
+	 * Resolution in days. The precision is the number of digits of days. It must have a value
+	 * between 1 and 6 (both inclusive). If no precision is specified, it is equal to 2 by default.
+	 */
+	public static Resolution DAY(int precision) {
 
 Review comment:
   Sounds good.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

Mime
View raw message