<commit_before>/**
 * END USER LICENSE AGREEMENT (“EULA”)
 *
 * READ THIS AGREEMENT CAREFULLY (date: 9/13/2011):
 * http://www.akiban.com/licensing/20110913
 *
 * BY INSTALLING OR USING ALL OR ANY PORTION OF THE SOFTWARE, YOU ARE ACCEPTING
 * ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. YOU AGREE THAT THIS
 * AGREEMENT IS ENFORCEABLE LIKE ANY WRITTEN AGREEMENT SIGNED BY YOU.
 *
 * IF YOU HAVE PAID A LICENSE FEE FOR USE OF THE SOFTWARE AND DO NOT AGREE TO
 * THESE TERMS, YOU MAY RETURN THE SOFTWARE FOR A FULL REFUND PROVIDED YOU (A) DO
 * NOT USE THE SOFTWARE AND (B) RETURN THE SOFTWARE WITHIN THIRTY (30) DAYS OF
 * YOUR INITIAL PURCHASE.
 *
 * IF YOU WISH TO USE THE SOFTWARE AS AN EMPLOYEE, CONTRACTOR, OR AGENT OF A
 * CORPORATION, PARTNERSHIP OR SIMILAR ENTITY, THEN YOU MUST BE AUTHORIZED TO SIGN
 * FOR AND BIND THE ENTITY IN ORDER TO ACCEPT THE TERMS OF THIS AGREEMENT. THE
 * LICENSES GRANTED UNDER THIS AGREEMENT ARE EXPRESSLY CONDITIONED UPON ACCEPTANCE
 * BY SUCH AUTHORIZED PERSONNEL.
 *
 * IF YOU HAVE ENTERED INTO A SEPARATE WRITTEN LICENSE AGREEMENT WITH AKIBAN FOR
 * USE OF THE SOFTWARE, THE TERMS AND CONDITIONS OF SUCH OTHER AGREEMENT SHALL
 * PREVAIL OVER ANY CONFLICTING TERMS OR CONDITIONS IN THIS AGREEMENT.
 */

package com.akiban.server.types3.mcompat.mfuncs;

import com.akiban.server.error.AkibanInternalException;
import com.akiban.server.error.InvalidDateFormatException;
import com.akiban.server.types3.LazyList;
import com.akiban.server.types3.TClass;
import com.akiban.server.types3.TCommutativeOverloads;
import com.akiban.server.types3.TCustomOverloadResult;
import com.akiban.server.types3.TExecutionContext;
import com.akiban.server.types3.TInstance;
import com.akiban.server.types3.TScalar;
import com.akiban.server.types3.TOverloadResult;
import com.akiban.server.types3.TPreptimeContext;
import com.akiban.server.types3.TPreptimeValue;
import com.akiban.server.types3.aksql.aktypes.AkInterval;
import com.akiban.server.types3.mcompat.mtypes.MApproximateNumber;
import com.akiban.server.types3.mcompat.mtypes.MDatetimes;
import com.akiban.server.types3.mcompat.mtypes.MDatetimes.StringType;
import com.akiban.server.types3.mcompat.mtypes.MString;
import com.akiban.server.types3.pvalue.PValueSource;
import com.akiban.server.types3.pvalue.PValueTarget;
import com.akiban.server.types3.texpressions.TInputSetBuilder;
import com.akiban.server.types3.texpressions.TScalarBase;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.joda.time.MutableDateTime;

public class MDateAddSub extends TScalarBase
{
    public static final TScalar[] COMMUTATIVE = new TScalar[]
    {
        //ADDDATE
        new MDateAddSub(Helper.DO_ADD, FirstType.DATE, SecondType.DAY, "ADDDATE"),
        new MDateAddSub(Helper.DO_ADD, FirstType.DATETIME, SecondType.DAY, "ADDDATE"),
        new MDateAddSub(Helper.DO_ADD, FirstType.TIMESTAMP, SecondType.DAY, "ADDDATE"),
        new AddSubWithVarchar(Helper.DO_ADD, SecondType.DAY, "ADDDATE"),
        new MDateAddSub(Helper.DO_ADD, FirstType.DATE, SecondType.INTERVAL_MILLIS, "DATE_ADD", "ADDDATE", "plus"),
        new MDateAddSub(Helper.DO_ADD_MONTH, FirstType.DATE, SecondType.INTERVAL_MONTH, "DATE_ADD", "ADDDATE", "plus"),
        new MDateAddSub(Helper.DO_ADD, FirstType.DATETIME, SecondType.INTERVAL_MILLIS, "DATE_ADD", "ADDDATE", "plus"),
        new MDateAddSub(Helper.DO_ADD_MONTH, FirstType.DATETIME, SecondType.INTERVAL_MONTH, "DATE_ADD", "ADDDATE", "plus"),
        new MDateAddSub(Helper.DO_ADD, FirstType.TIMESTAMP, SecondType.INTERVAL_MILLIS, "DATE_ADD", "ADDDATE", "plus"),
        new MDateAddSub(Helper.DO_ADD_MONTH, FirstType.TIMESTAMP, SecondType.INTERVAL_MONTH, "DATE_ADD", "ADDDATE", "plus"),
        new AddSubWithVarchar(Helper.DO_ADD, SecondType.INTERVAL_MILLIS, "DATE_ADD", "ADDDATE"),
        new AddSubWithVarchar(Helper.DO_ADD_MONTH, SecondType.INTERVAL_MONTH, "DATE_ADD", "ADDDATE"),

        // SUBDATE
        new MDateAddSub(Helper.DO_SUB, FirstType.DATE, SecondType.DAY, "SUBDATE"),
        new MDateAddSub(Helper.DO_SUB, FirstType.DATETIME, SecondType.DAY, "SUBDATE"),
        new MDateAddSub(Helper.DO_SUB, FirstType.TIMESTAMP, SecondType.DAY, "SUBDATE"),
        new AddSubWithVarchar(Helper.DO_SUB, SecondType.DAY, "SUBDATE"),
        new MDateAddSub(Helper.DO_SUB, FirstType.DATE, SecondType.INTERVAL_MILLIS, "DATE_SUB", "SUBDATE", "minus"),
        new MDateAddSub(Helper.DO_SUB_MONTH, FirstType.DATE, SecondType.INTERVAL_MONTH, "DATE_SUB", "SUBDATE", "minus"),
        new MDateAddSub(Helper.DO_SUB, FirstType.DATETIME, SecondType.INTERVAL_MILLIS, "DATE_SUB", "SUBDATE", "minus"),
        new MDateAddSub(Helper.DO_SUB_MONTH, FirstType.DATETIME, SecondType.INTERVAL_MONTH, "DATE_SUB", "SUBDATE", "minus"),
        new MDateAddSub(Helper.DO_SUB, FirstType.TIMESTAMP, SecondType.INTERVAL_MILLIS, "DATE_SUB", "SUBDATE", "minus"),
        new MDateAddSub(Helper.DO_SUB_MONTH, FirstType.TIMESTAMP, SecondType.INTERVAL_MONTH, "DATE_SUB", "SUBDATE", "minus"),
        
        // ADDTIME
        new MDateAddSub(Helper.DO_ADD, FirstType.TIME, SecondType.SECOND, "TIME_ADD", "ADDTIME"),
        new AddSubWithVarchar(Helper.DO_ADD, SecondType.SECOND, "TIME_ADD", "ADDTIME"),
        new AddSubWithVarchar(Helper.DO_ADD, SecondType.TIME, "TIME_ADD", "ADDTIME"),
        new MArithmetic.AlwaysNull("plus", "+", true, MDatetimes.TIME, AkInterval.MONTHS),
        new MArithmetic.AlwaysNull("plus", "+", true, MDatetimes.TIME, AkInterval.SECONDS),
        new MArithmetic.AlwaysNull("minus", "-", true, MDatetimes.TIME, AkInterval.MONTHS),
        new MArithmetic.AlwaysNull("minus", "-", true, MDatetimes.TIME, AkInterval.SECONDS),
    };

    public static final TScalar[] NON_COMMUTATIVE = new TScalar[]
    {
        new MDateAddSub(Helper.DO_ADD, FirstType.TIME, SecondType.TIME, "TIME_ADD", "ADDTIME"),
        new AddSubWithVarchar(Helper.DO_ADD, SecondType.TIME_STRING, "ADDTIME"),
        new AddSubWithVarchar(Helper.DO_SUB, SecondType.TIME_STRING, "SUBTIME"),
    };

    public static final TCommutativeOverloads COMMUTED = TCommutativeOverloads.createFrom(COMMUTATIVE);

    private static class AddSubWithVarchar extends MDateAddSub
    {
        AddSubWithVarchar (Helper h, SecondType sec, String...ns)
        {
            super(h, FirstType.VARCHAR, sec, ns);
        }
        
        @Override
        protected void doEvaluate(TExecutionContext context, LazyList<? extends PValueSource> inputs, PValueTarget output)
        {
            long ymd[] = new long[6];
            StringType stType;
            long millis;
            String arg0 = inputs.get(0).getString();
            try
            {
                stType = MDatetimes.parseDateOrTime(arg0, ymd);
                millis = secondArg.toMillis(inputs.get(1));
            }
            catch (InvalidDateFormatException e)
            {
                context.warnClient(e);
                output.putNull();
                return;
            }
            
            MutableDateTime dt;
            switch (stType)
            {
                case DATE_ST:
                    dt = MDatetimes.toJodaDatetime(ymd, "UTC");
                    helper.compute(dt, millis);
                    output.putString(dt.toString("YYYY-MM-dd"), null);
                    break;
                case DATETIME_ST:
                    dt = MDatetimes.toJodaDatetime(ymd, context.getCurrentTimezone());
                    helper.compute(dt, millis);
                    output.putString(dt.toString("YYYY-MM-dd hh:mm:ss"), null);
                    break;
                case TIME_ST:
                    long arg0Millis = timeToMillis(ymd);
                    
                    long ret = helper == Helper.DO_ADD ? arg0Millis + millis: arg0Millis - millis;
                    int sign = 1;
                    if (ret < 0)
                        ret *= (sign = -1);
                    
                    // turn millis back to hour-min-sec
                    long seconds = ret / 1000L;
                    long hours = seconds / 3600;
                    long minutes = (seconds - hours * 3600) / 60;
                    seconds -= (minutes * 60 + hours * 3600);
                    hours *= sign;
                    
                    output.putString(String.format("%02d:%02d:%02d",
                                                   hours, minutes, seconds),
                                     null);
                    break;
                default:
                    throw new AkibanInternalException("unexpected argument: " + stType);
            }
        }

        @Override
        public int[] getPriorities() {
            return new int[] { 2 };
        }
    }
    
    private static enum Helper
    {
        DO_ADD_MONTH
        {
            @Override
            protected void compute(MutableDateTime date, long delta)
            {
                date.addMonths((int)delta);
            }
        },
        DO_SUB_MONTH
        {
            @Override
            protected void compute(MutableDateTime date, long delta)
            {<commit_msg> - define <VARCHAR> { <plus> | <minus> } <INTERVAL> overloads  - Those overloads with VARCHAR don't need to have priority of 2<commit_after>/**
 * END USER LICENSE AGREEMENT (“EULA”)
 *
 * READ THIS AGREEMENT CAREFULLY (date: 9/13/2011):
 * http://www.akiban.com/licensing/20110913
 *
 * BY INSTALLING OR USING ALL OR ANY PORTION OF THE SOFTWARE, YOU ARE ACCEPTING
 * ALL OF THE TERMS AND CONDITIONS OF THIS AGREEMENT. YOU AGREE THAT THIS
 * AGREEMENT IS ENFORCEABLE LIKE ANY WRITTEN AGREEMENT SIGNED BY YOU.
 *
 * IF YOU HAVE PAID A LICENSE FEE FOR USE OF THE SOFTWARE AND DO NOT AGREE TO
 * THESE TERMS, YOU MAY RETURN THE SOFTWARE FOR A FULL REFUND PROVIDED YOU (A) DO
 * NOT USE THE SOFTWARE AND (B) RETURN THE SOFTWARE WITHIN THIRTY (30) DAYS OF
 * YOUR INITIAL PURCHASE.
 *
 * IF YOU WISH TO USE THE SOFTWARE AS AN EMPLOYEE, CONTRACTOR, OR AGENT OF A
 * CORPORATION, PARTNERSHIP OR SIMILAR ENTITY, THEN YOU MUST BE AUTHORIZED TO SIGN
 * FOR AND BIND THE ENTITY IN ORDER TO ACCEPT THE TERMS OF THIS AGREEMENT. THE
 * LICENSES GRANTED UNDER THIS AGREEMENT ARE EXPRESSLY CONDITIONED UPON ACCEPTANCE
 * BY SUCH AUTHORIZED PERSONNEL.
 *
 * IF YOU HAVE ENTERED INTO A SEPARATE WRITTEN LICENSE AGREEMENT WITH AKIBAN FOR
 * USE OF THE SOFTWARE, THE TERMS AND CONDITIONS OF SUCH OTHER AGREEMENT SHALL
 * PREVAIL OVER ANY CONFLICTING TERMS OR CONDITIONS IN THIS AGREEMENT.
 */

package com.akiban.server.types3.mcompat.mfuncs;

import com.akiban.server.error.AkibanInternalException;
import com.akiban.server.error.InvalidDateFormatException;
import com.akiban.server.types3.LazyList;
import com.akiban.server.types3.TClass;
import com.akiban.server.types3.TCommutativeOverloads;
import com.akiban.server.types3.TCustomOverloadResult;
import com.akiban.server.types3.TExecutionContext;
import com.akiban.server.types3.TInstance;
import com.akiban.server.types3.TScalar;
import com.akiban.server.types3.TOverloadResult;
import com.akiban.server.types3.TPreptimeContext;
import com.akiban.server.types3.TPreptimeValue;
import com.akiban.server.types3.aksql.aktypes.AkInterval;
import com.akiban.server.types3.mcompat.mtypes.MApproximateNumber;
import com.akiban.server.types3.mcompat.mtypes.MDatetimes;
import com.akiban.server.types3.mcompat.mtypes.MDatetimes.StringType;
import com.akiban.server.types3.mcompat.mtypes.MString;
import com.akiban.server.types3.pvalue.PValueSource;
import com.akiban.server.types3.pvalue.PValueTarget;
import com.akiban.server.types3.texpressions.TInputSetBuilder;
import com.akiban.server.types3.texpressions.TScalarBase;
import java.util.List;
import java.util.concurrent.TimeUnit;

import org.joda.time.MutableDateTime;

public class MDateAddSub extends TScalarBase
{
    public static final TScalar[] COMMUTATIVE = new TScalar[]
    {
        //ADDDATE
        new MDateAddSub(Helper.DO_ADD, FirstType.DATE, SecondType.DAY, "ADDDATE"),
        new MDateAddSub(Helper.DO_ADD, FirstType.DATETIME, SecondType.DAY, "ADDDATE"),
        new MDateAddSub(Helper.DO_ADD, FirstType.TIMESTAMP, SecondType.DAY, "ADDDATE"),
        new AddSubWithVarchar(Helper.DO_ADD, SecondType.DAY, "ADDDATE"),
        new MDateAddSub(Helper.DO_ADD, FirstType.DATE, SecondType.INTERVAL_MILLIS, "DATE_ADD", "ADDDATE", "plus"),
        new MDateAddSub(Helper.DO_ADD_MONTH, FirstType.DATE, SecondType.INTERVAL_MONTH, "DATE_ADD", "ADDDATE", "plus"),
        new MDateAddSub(Helper.DO_ADD, FirstType.DATETIME, SecondType.INTERVAL_MILLIS, "DATE_ADD", "ADDDATE", "plus"),
        new MDateAddSub(Helper.DO_ADD_MONTH, FirstType.DATETIME, SecondType.INTERVAL_MONTH, "DATE_ADD", "ADDDATE", "plus"),
        new MDateAddSub(Helper.DO_ADD, FirstType.TIMESTAMP, SecondType.INTERVAL_MILLIS, "DATE_ADD", "ADDDATE", "plus"),
        new MDateAddSub(Helper.DO_ADD_MONTH, FirstType.TIMESTAMP, SecondType.INTERVAL_MONTH, "DATE_ADD", "ADDDATE", "plus"),
        new AddSubWithVarchar(Helper.DO_ADD, SecondType.INTERVAL_MILLIS, "DATE_ADD", "ADDDATE", "plus"),
        new AddSubWithVarchar(Helper.DO_ADD_MONTH, SecondType.INTERVAL_MONTH, "DATE_ADD", "ADDDATE", "plus"),

        // SUBDATE
        new MDateAddSub(Helper.DO_SUB, FirstType.DATE, SecondType.DAY, "SUBDATE"),
        new MDateAddSub(Helper.DO_SUB, FirstType.DATETIME, SecondType.DAY, "SUBDATE"),
        new MDateAddSub(Helper.DO_SUB, FirstType.TIMESTAMP, SecondType.DAY, "SUBDATE"),
        new AddSubWithVarchar(Helper.DO_SUB, SecondType.DAY, "SUBDATE"),
        new MDateAddSub(Helper.DO_SUB, FirstType.DATE, SecondType.INTERVAL_MILLIS, "DATE_SUB", "SUBDATE", "minus"),
        new MDateAddSub(Helper.DO_SUB_MONTH, FirstType.DATE, SecondType.INTERVAL_MONTH, "DATE_SUB", "SUBDATE", "minus"),
        new MDateAddSub(Helper.DO_SUB, FirstType.DATETIME, SecondType.INTERVAL_MILLIS, "DATE_SUB", "SUBDATE", "minus"),
        new MDateAddSub(Helper.DO_SUB_MONTH, FirstType.DATETIME, SecondType.INTERVAL_MONTH, "DATE_SUB", "SUBDATE", "minus"),
        new MDateAddSub(Helper.DO_SUB, FirstType.TIMESTAMP, SecondType.INTERVAL_MILLIS, "DATE_SUB", "SUBDATE", "minus"),
        new MDateAddSub(Helper.DO_SUB_MONTH, FirstType.TIMESTAMP, SecondType.INTERVAL_MONTH, "DATE_SUB", "SUBDATE", "minus"),
        new AddSubWithVarchar(Helper.DO_SUB, SecondType.INTERVAL_MILLIS, "DATE_SUB", "SUBDATE", "minus"),
        new AddSubWithVarchar(Helper.DO_SUB_MONTH, SecondType.INTERVAL_MONTH, "DATE_SUB", "SUBDATE", "minus"),
        
        // ADDTIME
        new MDateAddSub(Helper.DO_ADD, FirstType.TIME, SecondType.SECOND, "TIME_ADD", "ADDTIME"),
        new AddSubWithVarchar(Helper.DO_ADD, SecondType.SECOND, "TIME_ADD", "ADDTIME"),
        new AddSubWithVarchar(Helper.DO_ADD, SecondType.TIME, "TIME_ADD", "ADDTIME"),
        new MArithmetic.AlwaysNull("plus", "+", true, MDatetimes.TIME, AkInterval.MONTHS),
        new MArithmetic.AlwaysNull("plus", "+", true, MDatetimes.TIME, AkInterval.SECONDS),
        new MArithmetic.AlwaysNull("minus", "-", true, MDatetimes.TIME, AkInterval.MONTHS),
        new MArithmetic.AlwaysNull("minus", "-", true, MDatetimes.TIME, AkInterval.SECONDS),
    };

    public static final TScalar[] NON_COMMUTATIVE = new TScalar[]
    {
        new MDateAddSub(Helper.DO_ADD, FirstType.TIME, SecondType.TIME, "TIME_ADD", "ADDTIME"),
        new AddSubWithVarchar(Helper.DO_ADD, SecondType.TIME_STRING, "ADDTIME"),
        new AddSubWithVarchar(Helper.DO_SUB, SecondType.TIME_STRING, "SUBTIME"),
    };

    public static final TCommutativeOverloads COMMUTED = TCommutativeOverloads.createFrom(COMMUTATIVE);

    private static class AddSubWithVarchar extends MDateAddSub
    {
        AddSubWithVarchar (Helper h, SecondType sec, String...ns)
        {
            super(h, FirstType.VARCHAR, sec, ns);
        }
        
        @Override
        protected void doEvaluate(TExecutionContext context, LazyList<? extends PValueSource> inputs, PValueTarget output)
        {
            long ymd[] = new long[6];
            StringType stType;
            long millis;
            String arg0 = inputs.get(0).getString();
            try
            {
                stType = MDatetimes.parseDateOrTime(arg0, ymd);
                millis = secondArg.toMillis(inputs.get(1));
            }
            catch (InvalidDateFormatException e)
            {
                context.warnClient(e);
                output.putNull();
                return;
            }
            
            MutableDateTime dt;
            switch (stType)
            {
                case DATE_ST:
                    dt = MDatetimes.toJodaDatetime(ymd, "UTC");
                    helper.compute(dt, millis);
                    output.putString(dt.toString("YYYY-MM-dd"), null);
                    break;
                case DATETIME_ST:
                    dt = MDatetimes.toJodaDatetime(ymd, context.getCurrentTimezone());
                    helper.compute(dt, millis);
                    output.putString(dt.toString("YYYY-MM-dd HH:mm:ss"), null);
                    break;
                case TIME_ST:
                    long arg0Millis = timeToMillis(ymd);
                    
                    long ret = helper == Helper.DO_ADD ? arg0Millis + millis: arg0Millis - millis;
                    int sign = 1;
                    if (ret < 0)
                        ret *= (sign = -1);
                    
                    // turn millis back to hour-min-sec
                    long seconds = ret / 1000L;
                    long hours = seconds / 3600;
                    long minutes = (seconds - hours * 3600) / 60;
                    seconds -= (minutes * 60 + hours * 3600);
                    hours *= sign;
                    
                    output.putString(String.format("%02d:%02d:%02d",
                                                   hours, minutes, seconds),
                                     null);
                    break;
                default:
                    throw new AkibanInternalException("unexpected argument: " + stType);
            }
        }
    }
    
    private static enum Helper
    {
        DO_ADD_MONTH
        {
            @Override
            protected void compute(MutableDateTime date, long delta)
            {
                date.addMonths((int)delta);
            }
        },
        DO_SUB_MONTH
        {
            @Override
            protected void compute(MutableDateTime date, long delta)
            {
{'fraction_non_alphanumeric': 0.10223330442324371, 'fraction_numerical': 0.00813096270598439, 'mean_word_length': 2.653990889285007, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2371520', 'n_tokens_mistral': 6010, 'n_tokens_neox': 5740, 'n_words': 1253}