| /* |
| * 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); |
| } |
| |
| } |