Search in sources :

Example 1 with DataTypePattern

use of io.debezium.relational.ddl.DataTypeGrammarParser.DataTypePattern in project debezium by debezium.

the class DataTypeParser method parse.

/**
 * Examine the stream starting at its current position for a matching data type. If this method finds a matching data type,
 * it will consume the stream of all tokens that make up the data type. However, if no data type is found, the stream is left
 * unchanged.
 * <p>
 * This method looks for data types that match those registered patterns.
 * This method also looks for multi-dimensional arrays, where any registered data type pattern is followed by one or more
 * array dimensions of the form {@code [n]}, where {@code n} is the integer dimension.
 * <p>
 * Sometimes, a data type matches one of the registered patterns but it contains a malformed length/precision, scale, and/or
 * array dimensions. These parsing exceptions can be reported back to the caller via the supplied {@code errorHandler},
 * although these errors are only reported when no data type is found. This is often useful when the caller expects
 * to find a data type, but no such data type can be found due to one or more parsing exceptions. When this happens,
 * the method calls {@code errorHandler} with all of the {@link ParsingException}s and then returns <code>null</code>.
 *
 * @param stream the stream of tokens; may not be null
 * @param errorHandler a function that should be called when no data type was found because at least one
 *            {@link ParsingException}
 *            occurred with the length/precision, scale, and/or array dimensions; may be null
 * @return the data type if one was found, or null if none were found
 */
public DataType parse(TokenStream stream, Consumer<Collection<ParsingException>> errorHandler) {
    if (stream.hasNext()) {
        // Look for all patterns that begin with the first token ...
        Collection<DataTypePattern> matchingPatterns = patterns.get(stream.peek().toUpperCase());
        if (matchingPatterns != null) {
            // At least one registered type begins with the first token, so go through them all in order ...
            ErrorCollector errors = new ErrorCollector();
            Marker mostReadMarker = null;
            DataType mostReadType = null;
            Marker marker = stream.mark();
            for (DataTypePattern pattern : matchingPatterns) {
                DataType result = pattern.match(stream, errors::record);
                if (result != null) {
                    // We found a match, so record it if it is better than our previous best ...
                    if (!stream.hasNext()) {
                        // There's no more to read, so we should be done ...
                        return result;
                    }
                    Marker endMarker = stream.mark();
                    if (mostReadMarker == null || endMarker.compareTo(mostReadMarker) > 0) {
                        mostReadMarker = endMarker;
                        mostReadType = result;
                    }
                }
                // always, even in the case of success
                stream.rewind(marker);
            }
            if (mostReadType != null) {
                // We've found at least one, so advance the stream to the end of what was consumed by that data type
                // and return the type that consumes the most of the stream ...
                stream.advance(mostReadMarker);
                return mostReadType;
            }
            // We still haven't found a data type ...
            errors.send(errorHandler);
        }
    }
    // Ultimately did not find a match ...
    return null;
}
Also used : DataTypePattern(io.debezium.relational.ddl.DataTypeGrammarParser.DataTypePattern) Marker(io.debezium.text.TokenStream.Marker)

Example 2 with DataTypePattern

use of io.debezium.relational.ddl.DataTypeGrammarParser.DataTypePattern in project debezium by debezium.

the class DataTypeParser method register.

/**
 * Register data type that may not contain a length/precision or scale.
 * <p>
 * The order that grammars are registered is the same order that they are evaluated by the resulting parser. However, when
 * multiple grammars match the same input tokens, the grammar that successfully consumes the most input tokens will be
 * selected.
 *
 * @param jdbcType the best JDBC type for the data type
 * @param grammar the grammar the defines the data type format; may not be null
 * @return this parser so callers can chain methods; never null
 */
public DataTypeParser register(int jdbcType, String grammar) {
    Objects.requireNonNull(grammar, "the data type grammar must be specified");
    DataTypePattern pattern = parser.parse(jdbcType, grammar);
    pattern.forEachFirstToken(token -> {
        patterns.computeIfAbsent(token, (key) -> new ArrayList<DataTypePattern>()).add(pattern);
    });
    return this;
}
Also used : Objects(java.util.Objects) Consumer(java.util.function.Consumer) DataTypePattern(io.debezium.relational.ddl.DataTypeGrammarParser.DataTypePattern) ParsingException(io.debezium.text.ParsingException) TokenStream(io.debezium.text.TokenStream) Collection(java.util.Collection) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Marker(io.debezium.text.TokenStream.Marker) ThreadSafe(io.debezium.annotation.ThreadSafe) ArrayList(java.util.ArrayList) DataTypePattern(io.debezium.relational.ddl.DataTypeGrammarParser.DataTypePattern) ArrayList(java.util.ArrayList)

Aggregations

DataTypePattern (io.debezium.relational.ddl.DataTypeGrammarParser.DataTypePattern)2 Marker (io.debezium.text.TokenStream.Marker)2 ThreadSafe (io.debezium.annotation.ThreadSafe)1 ParsingException (io.debezium.text.ParsingException)1 TokenStream (io.debezium.text.TokenStream)1 ArrayList (java.util.ArrayList)1 Collection (java.util.Collection)1 Map (java.util.Map)1 Objects (java.util.Objects)1 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)1 Consumer (java.util.function.Consumer)1