/*
* ModeShape (http://www.modeshape.org)
*
* Licensed 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.modeshape.sequencer.ddl.dialect.teiid;
import org.modeshape.common.text.ParsingException;
import org.modeshape.sequencer.ddl.DdlTokenStream;
import org.modeshape.sequencer.ddl.datatype.DataType;
import org.modeshape.sequencer.ddl.datatype.DataTypeParser;
import org.modeshape.sequencer.ddl.dialect.teiid.TeiidDdlConstants.TeiidDataType;
class TeiidDataTypeParser extends DataTypeParser {
static final int[] DEFAULT_PRECISION_SCALE = new int[] {DataType.DEFAULT_PRECISION, DataType.DEFAULT_SCALE};
/**
* {@inheritDoc}
*
* @see org.modeshape.sequencer.ddl.datatype.DataTypeParser#isCustomDataType(org.modeshape.sequencer.ddl.DdlTokenStream)
*/
@Override
protected boolean isCustomDataType( final DdlTokenStream tokens ) throws ParsingException {
throw new TeiidDdlParsingException(tokens, "isCustomDataType(DdlTokenStream) should not be called");
}
/**
* {@inheritDoc}
*
* @see org.modeshape.sequencer.ddl.datatype.DataTypeParser#parse(org.modeshape.sequencer.ddl.DdlTokenStream)
*/
@Override
public DataType parse( final DdlTokenStream tokens ) throws ParsingException {
TeiidDataType teiidType = null;
long length = DataType.DEFAULT_LENGTH;
int[] precisionScale = DEFAULT_PRECISION_SCALE;
for (final TeiidDataType teiidDataType : TeiidDataType.values()) {
if (tokens.canConsume(teiidDataType.toDdl())) {
teiidType = teiidDataType;
if (teiidDataType == TeiidDataType.BIGDECIMAL) {
// ( BIGDECIMAL ( <lparen> <unsigned integer> ( <comma> <unsigned integer> )? <rparen> )? )
precisionScale = parseDecimal(tokens);
} else if (teiidDataType == TeiidDataType.BIGINTEGER) {
// ( BIGINTEGER ( <lparen> <unsigned integer> <rparen> )? )
length = parseLength(tokens);
} else if (teiidDataType == TeiidDataType.BLOB) {
// ( BLOB ( <lparen> <unsigned integer> <rparen> )? )
length = parseLength(tokens);
} else if (teiidDataType == TeiidDataType.CHAR) {
// ( CHAR ( <lparen> <unsigned integer> <rparen> )? )
length = parseLength(tokens);
} else if (teiidDataType == TeiidDataType.CLOB) {
// ( CLOB ( <lparen> <unsigned integer> <rparen> )? )
length = parseLength(tokens);
} else if (teiidDataType == TeiidDataType.DECIMAL) {
// ( DECIMAL ( <lparen> <unsigned integer> ( <comma> <unsigned integer> )? <rparen> )? )
precisionScale = parseDecimal(tokens);
} else if (teiidDataType == TeiidDataType.STRING) {
// ( STRING ( <lparen> <unsigned integer> <rparen> )? )
length = parseLength(tokens);
} else if (teiidDataType == TeiidDataType.VARBINARY) {
// ( VARBINARY ( <lparen> <unsigned integer> <rparen> )? )
length = parseLength(tokens);
} else if (teiidDataType == TeiidDataType.VARCHAR) {
// ( VARCHAR ( <lparen> <unsigned integer> <rparen> )? )
length = parseLength(tokens);
} else if (teiidDataType == TeiidDataType.OBJECT) {
// ( OBJECT ( <lparen> <unsigned integer> <rparen> )? )
length = parseLength(tokens);
}
break;
}
}
if (teiidType != null) {
final DataType type = new DataType(teiidType.toDdl());
// set length
if (length != DataType.DEFAULT_LENGTH) {
type.setLength(length);
}
// set precision and scale
assert ((precisionScale != null) && (precisionScale.length > 0));
if (precisionScale != DEFAULT_PRECISION_SCALE) {
if (precisionScale[0] != DataType.DEFAULT_PRECISION) {
type.setPrecision(precisionScale[0]);
}
if ((precisionScale.length == 2) && (precisionScale[1] != DataType.DEFAULT_SCALE)) {
type.setScale(precisionScale[1]);
}
}
return type;
}
throw new TeiidDdlParsingException(tokens, "Unparsable data type");
}
/**
* <code>
* ( BIGDECIMAL ( <lparen> <unsigned integer> ( <comma> <unsigned integer> )? <rparen> )? )
* </code>
*
* @param tokens the tokens being processed (cannot be <code>null</code>)
* @return a long array of length one containing the precision, a long array of length two containing precision and scale, or
* <code>null</code> if precision and scale are not found
* @throws NumberFormatException if the precision or scale is not an int
*/
private int[] parseDecimal( final DdlTokenStream tokens ) {
if (tokens.canConsume(L_PAREN)) {
int precision = Integer.parseInt(tokens.consume());
int scale = DataType.DEFAULT_SCALE;
if (tokens.canConsume(COMMA)) {
scale = Integer.parseInt(tokens.consume());
}
tokens.consume(R_PAREN); // right paren
if (scale == DataType.DEFAULT_SCALE) {
return new int[] {precision};
}
return new int[] {precision, scale};
}
return DEFAULT_PRECISION_SCALE;
}
/**
* <code>
* ( <lparen> <unsigned integer> <rparen> )?
* </code>
*
* @param tokens the tokens being processed (cannot be <code>null</code>)
* @return the length or the default length if length is not found
* @see DataType#DEFAULT_LENGTH
*/
private long parseLength( final DdlTokenStream tokens ) {
if (tokens.canConsume(L_PAREN)) {
final String value = tokens.consume();
tokens.consume(R_PAREN);
return parseLong(value);
}
return DataType.DEFAULT_LENGTH;
}
}