Package com.foundationdb.server.types.mcompat.mfuncs

Source Code of com.foundationdb.server.types.mcompat.mfuncs.MTimestampDiff

/**
* Copyright (C) 2009-2013 FoundationDB, LLC
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package com.foundationdb.server.types.mcompat.mfuncs;

import com.foundationdb.server.error.InvalidDateFormatException;
import com.foundationdb.server.types.LazyList;
import com.foundationdb.server.types.TClass;
import com.foundationdb.server.types.TExecutionContext;
import com.foundationdb.server.types.TOverloadResult;
import com.foundationdb.server.types.TScalar;
import com.foundationdb.server.types.mcompat.mtypes.MDateAndTime;
import com.foundationdb.server.types.mcompat.mtypes.MDateAndTime.StringType;
import com.foundationdb.server.types.mcompat.mtypes.MDateAndTime.ZeroFlag;
import com.foundationdb.server.types.mcompat.mtypes.MNumeric;
import com.foundationdb.server.types.mcompat.mtypes.MString;
import com.foundationdb.server.types.value.ValueSource;
import com.foundationdb.server.types.value.ValueTarget;
import com.foundationdb.server.types.texpressions.TInputSetBuilder;
import com.foundationdb.server.types.texpressions.TScalarBase;
import com.foundationdb.sql.parser.TernaryOperatorNode;

public class MTimestampDiff extends TScalarBase
{
    public static TScalar[] create()
    {
        ArgType args[] = ArgType.values();
        TScalar ret[] = new TScalar[args.length * args.length + 1];
        int n = 0;
       
        for (ArgType arg1 : args)
            for (ArgType arg2 : args)
                ret[n++] = new MTimestampDiff(arg1, arg2)
                {
                    public int[] getPriorities() {return new int[] {0};}
                };
       
        // create a second group prio group, forcing all arguments be
        // casted to the formal types
        ret[n] = new MTimestampDiff(ArgType.TIMESTAMP, ArgType.TIMESTAMP)
        {
            public int[] getPriorities() {return new int[] {1};}
        };
       
        return ret;
    }
   
    private static enum ArgType
    {
        DATE(MDateAndTime.DATE)
        {
            @Override
            long[] getYMD(ValueSource source, TExecutionContext context)
            {
                int date = source.getInt32();
                long ymd[] = MDateAndTime.decodeDate(date);

                if (MDateAndTime.isValidDateTime(ymd, ZeroFlag.YEAR))
                    return ymd;
                else
                {
                    context.warnClient(new InvalidDateFormatException("DATE",
                                                                      MDateAndTime.dateToString(date)));
                    return null;
                }
            }
        },
        DATETIME(MDateAndTime.DATETIME)
        {
            @Override
            long[] getYMD(ValueSource source, TExecutionContext context)
            {
                long datetime = source.getInt64();
                long ymd[] = MDateAndTime.decodeDateTime(datetime);
               
                if (MDateAndTime.isValidDateTime(ymd, ZeroFlag.YEAR))
                    return ymd;
                else
                {
                    context.warnClient(new InvalidDateFormatException("DATETIME",
                                                                      MDateAndTime.dateTimeToString(datetime)));
                    return null;
                }
            }
        },
        TIMESTAMP(MDateAndTime.TIMESTAMP)
        {
            @Override
            long [] getYMD(ValueSource source, TExecutionContext context)
            {
                return MDateAndTime.decodeTimestamp(source.getInt32(), "UTC"/*context.getCurrentTimezone()*/);
            }
           
            // override this because TIMESTAMP type doesn't need to go thru the decoding process
            // just return whatever is passed in
            @Override
            Long getUnix(ValueSource source, TExecutionContext context)
            {
                return source.getInt32() * 1000L; // unix
            }
        },
        VARCHAR(MString.VARCHAR)
        {
            @Override
            long [] getYMD(ValueSource source, TExecutionContext context)
            {
                long ymd[] = new long[6];
                StringType strType = MDateAndTime.parseDateOrTime(source.getString(), ymd);
                if (strType == StringType.TIME_ST || !MDateAndTime.isValidType(strType)) {
                    context.warnClient(new InvalidDateFormatException("DATETIME", source.getString()));
                    return null;
                }
                return ymd;
            }
        }
        ;
       
        abstract long[] getYMD(ValueSource source, TExecutionContext context);
       
        Long getUnix(ValueSource source, TExecutionContext context)
        {
            long ymd[] = getYMD(source, context);

            return ymd == null
                    ? null
                    : MDateAndTime.getTimestamp(ymd, "UTC") * 1000L; // use UTC to do the computation
        }
       
        private ArgType(TClass type)
        {
            this.type = type;
        }
        private final TClass type;
    }
   
   
    private final ArgType arg1;
    private final ArgType arg2;
   
    private MTimestampDiff(ArgType arg1, ArgType arg2)
    {
        this.arg1 = arg1;
        this.arg2 = arg2;
    }
   
    @Override
    protected void buildInputSets(TInputSetBuilder builder)
    {
        builder.covers(MNumeric.INT, 0).covers(arg1.type, 1).covers(arg2.type, 2);
    }
   
    @Override
    protected void doEvaluate(TExecutionContext context, LazyList<? extends ValueSource> inputs, ValueTarget output)
    {
        int unit = inputs.get(0).getInt32();
       
        ValueSource date1 = inputs.get(1);
        ValueSource date2 = inputs.get(2);
       
        switch(unit)
        {
            case TernaryOperatorNode.YEAR_INTERVAL:
            case TernaryOperatorNode.QUARTER_INTERVAL:
            case TernaryOperatorNode.MONTH_INTERVAL:
                doMonthSubtraction(arg2.getYMD(date2, context),
                                   arg1.getYMD(date1, context),
                                   MONTH_DIV[unit - MONTH_BASE],
                                   output);
                break;
            case TernaryOperatorNode.WEEK_INTERVAL:
            case TernaryOperatorNode.DAY_INTERVAL:
            case TernaryOperatorNode.HOUR_INTERVAL:
            case TernaryOperatorNode.MINUTE_INTERVAL:
            case TernaryOperatorNode.SECOND_INTERVAL:
            case TernaryOperatorNode.FRAC_SECOND_INTERVAL:
                Long unix1, unix2 = 0L;
                if ((unix1 = arg1.getUnix(date1, context)) == null
                        || (unix2 = arg2.getUnix(date2, context)) == null)
                    output.putNull();
                else
                    output.putInt64((unix2 - unix1) / MILLIS_DIV[unit - MILLIS_BASE]);
                break;
            default:
                        throw new UnsupportedOperationException("Unknown UNIT: " + unit);
       
        }
    }

    @Override
    public String displayName()
    {
        return "TIMESTAMPDIFF";
    }

    @Override
    public TOverloadResult resultType()
    {
        return TOverloadResult.fixed(MNumeric.BIGINT, 21);
    }
   
    // ------------ static members --------------
    private static final long[] MILLIS_DIV = new long[6];
    private static final int[] MONTH_DIV = {12, 4, 1};

    private static final int MILLIS_BASE = TernaryOperatorNode.WEEK_INTERVAL;
    private static final int MONTH_BASE = TernaryOperatorNode.YEAR_INTERVAL;
    static
    {
        int mul[] ={7, 24, 60, 60, 1000};

        MILLIS_DIV[5] = 1;
        for (int n = 4; n >= 0; --n)
            MILLIS_DIV[n] = MILLIS_DIV[n + 1] * mul[n];
    }
   
    private static void doMonthSubtraction (long d1[], long d2[], long divisor, ValueTarget out)
    {
        if (d1 == null || d2 == null)
        {
            out.putNull();
            return;
        }
        long ret = (d1[0] - d2[0]) * 12 + d1[1] - d2[1];

        // adjust the day difference
        if (ret > 0 && d1[2] < d2[2]) --ret;
        else if (ret < 0 && d1[2] > d2[2]) ++ret;

        out.putInt64(ret / divisor);
    }

}
TOP

Related Classes of com.foundationdb.server.types.mcompat.mfuncs.MTimestampDiff

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.