blob: 8117d0ebbd006b377873eeee54381c6275aad052 [file] [log] [blame]
/*
* 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.vxquery.runtime.functions.cast;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.vxquery.datamodel.accessors.atomic.XSDecimalPointable;
import org.apache.vxquery.datamodel.values.ValueTag;
import org.apache.vxquery.exceptions.ErrorCode;
import org.apache.vxquery.exceptions.SystemException;
import org.apache.vxquery.runtime.functions.strings.ICharacterIterator;
import org.apache.vxquery.runtime.functions.strings.UTF8StringCharacterIterator;
import org.apache.hyracks.data.std.api.INumeric;
import org.apache.hyracks.data.std.primitive.BooleanPointable;
import org.apache.hyracks.data.std.primitive.BytePointable;
import org.apache.hyracks.data.std.primitive.DoublePointable;
import org.apache.hyracks.data.std.primitive.FloatPointable;
import org.apache.hyracks.data.std.primitive.IntegerPointable;
import org.apache.hyracks.data.std.primitive.LongPointable;
import org.apache.hyracks.data.std.primitive.ShortPointable;
import org.apache.hyracks.data.std.primitive.UTF8StringPointable;
import org.apache.hyracks.data.std.util.ArrayBackedValueStorage;
public class CastToDecimalOperation extends AbstractCastToOperation {
private ArrayBackedValueStorage abvsInner = new ArrayBackedValueStorage();
private DataOutput dOutInner = abvsInner.getDataOutput();
private CastToStringOperation castToString = new CastToStringOperation();
private UTF8StringPointable stringp = (UTF8StringPointable) UTF8StringPointable.FACTORY.createPointable();
@Override
public void convertBoolean(BooleanPointable boolp, DataOutput dOut) throws SystemException, IOException {
long value = (boolp.getBoolean() ? 1 : 0);
dOut.write(ValueTag.XS_DECIMAL_TAG);
dOut.writeByte(0);
dOut.writeLong(value);
}
@Override
public void convertDecimal(XSDecimalPointable decp, DataOutput dOut) throws SystemException, IOException {
dOut.write(ValueTag.XS_DECIMAL_TAG);
dOut.write(decp.getByteArray(), decp.getStartOffset(), decp.getLength());
}
@Override
public void convertDouble(DoublePointable doublep, DataOutput dOut) throws SystemException, IOException {
if (doublep.getDouble() == 0) {
long bits = Double.doubleToLongBits(doublep.getDouble());
boolean negative = ((bits >> 63) == 0) ? false : true;
if (negative) {
throw new SystemException(ErrorCode.FORG0001);
}
}
if (Double.isNaN(doublep.getDouble()) || Double.isInfinite(doublep.getDouble())) {
throw new SystemException(ErrorCode.FORG0001);
}
abvsInner.reset();
dOutInner.write(ValueTag.XS_STRING_TAG);
dOutInner.writeUTF(Double.toString(doublep.getDouble()));
stringp.set(abvsInner.getByteArray(), abvsInner.getStartOffset() + 1, abvsInner.getLength() - 1);
convertStringExtra(stringp, dOut, true);
}
@Override
public void convertFloat(FloatPointable floatp, DataOutput dOut) throws SystemException, IOException {
if (floatp.getFloat() == 0) {
long bits = Float.floatToIntBits(floatp.getFloat());
boolean negative = ((bits >> 31) == 0) ? false : true;
if (negative) {
throw new SystemException(ErrorCode.FORG0001);
}
}
abvsInner.reset();
castToString.convertFloatCanonical(floatp, dOutInner);
stringp.set(abvsInner.getByteArray(), abvsInner.getStartOffset() + 1, abvsInner.getLength() - 1);
convertStringExtra(stringp, dOut, true);
}
@Override
public void convertInteger(LongPointable longp, DataOutput dOut) throws SystemException, IOException {
writeIntegerAsDecimal(longp, dOut);
}
@Override
public void convertString(UTF8StringPointable stringp, DataOutput dOut) throws SystemException, IOException {
convertStringExtra(stringp, dOut, false);
}
private void convertStringExtra(UTF8StringPointable stringp, DataOutput dOut, boolean connoicalForm)
throws SystemException, IOException {
ICharacterIterator charIterator = new UTF8StringCharacterIterator(stringp);
charIterator.reset();
byte decimalPlace = 0;
long value = 0;
boolean pastDecimal = false, negativeValue = false;
int count = 0;
int c = 0;
// Check sign.
c = charIterator.next();
if (c == Character.valueOf('-')) {
negativeValue = true;
c = charIterator.next();
}
// Read in the number.
do {
if (count + 1 > XSDecimalPointable.PRECISION) {
throw new SystemException(ErrorCode.FOCA0006);
} else if (Character.isDigit(c)) {
value = value * 10 + Character.getNumericValue(c);
if (pastDecimal) {
decimalPlace++;
}
count++;
} else if (c == Character.valueOf('.') && pastDecimal == false) {
pastDecimal = true;
} else if (c == Character.valueOf('E') || c == Character.valueOf('e') && connoicalForm) {
break;
} else {
throw new SystemException(ErrorCode.FORG0001);
}
} while ((c = charIterator.next()) != ICharacterIterator.EOS_CHAR);
// Parse the exponent.
if (c == Character.valueOf('E') || c == Character.valueOf('e') && connoicalForm) {
int moveOffset = 0;
boolean negativeOffset = false;
// Check for the negative sign.
c = charIterator.next();
if (c == Character.valueOf('-')) {
negativeOffset = true;
c = charIterator.next();
}
// Process the numeric value.
do {
if (Character.isDigit(c)) {
moveOffset = moveOffset * 10 + Character.getNumericValue(c);
} else {
throw new SystemException(ErrorCode.FORG0001);
}
} while ((c = charIterator.next()) != ICharacterIterator.EOS_CHAR);
decimalPlace -= (negativeOffset ? -moveOffset : moveOffset);
}
// Normalize the value and take off trailing zeros.
while (value != 0 && value % 10 == 0) {
value /= 10;
--decimalPlace;
}
if (decimalPlace > XSDecimalPointable.PRECISION) {
throw new SystemException(ErrorCode.FOCA0006);
}
dOut.write(ValueTag.XS_DECIMAL_TAG);
dOut.write(decimalPlace);
dOut.writeLong((negativeValue ? -value : value));
}
@Override
public void convertUntypedAtomic(UTF8StringPointable stringp, DataOutput dOut) throws SystemException, IOException {
convertString(stringp, dOut);
}
/**
* Derived Datatypes
*/
public void convertByte(BytePointable bytep, DataOutput dOut) throws SystemException, IOException {
writeIntegerAsDecimal(bytep, dOut);
}
public void convertInt(IntegerPointable intp, DataOutput dOut) throws SystemException, IOException {
writeIntegerAsDecimal(intp, dOut);
}
public void convertLong(LongPointable longp, DataOutput dOut) throws SystemException, IOException {
writeIntegerAsDecimal(longp, dOut);
}
public void convertNegativeInteger(LongPointable longp, DataOutput dOut) throws SystemException, IOException {
writeIntegerAsDecimal(longp, dOut);
}
public void convertNonNegativeInteger(LongPointable longp, DataOutput dOut) throws SystemException, IOException {
writeIntegerAsDecimal(longp, dOut);
}
public void convertNonPositiveInteger(LongPointable longp, DataOutput dOut) throws SystemException, IOException {
writeIntegerAsDecimal(longp, dOut);
}
public void convertPositiveInteger(LongPointable longp, DataOutput dOut) throws SystemException, IOException {
writeIntegerAsDecimal(longp, dOut);
}
public void convertShort(ShortPointable shortp, DataOutput dOut) throws SystemException, IOException {
writeIntegerAsDecimal(shortp, dOut);
}
public void convertUnsignedByte(ShortPointable shortp, DataOutput dOut) throws SystemException, IOException {
writeIntegerAsDecimal(shortp, dOut);
}
public void convertUnsignedInt(LongPointable longp, DataOutput dOut) throws SystemException, IOException {
writeIntegerAsDecimal(longp, dOut);
}
public void convertUnsignedLong(LongPointable longp, DataOutput dOut) throws SystemException, IOException {
writeIntegerAsDecimal(longp, dOut);
}
public void convertUnsignedShort(IntegerPointable intp, DataOutput dOut) throws SystemException, IOException {
writeIntegerAsDecimal(intp, dOut);
}
private void writeIntegerAsDecimal(INumeric numericp, DataOutput dOut) throws SystemException, IOException {
byte decimalPlace = 0;
long value = numericp.longValue();
// Normalize the value and take off trailing zeros.
while (value != 0 && value % 10 == 0) {
value /= 10;
--decimalPlace;
}
dOut.write(ValueTag.XS_DECIMAL_TAG);
dOut.write(decimalPlace);
dOut.writeLong(value);
}
}