Package org.voltdb.utils

Source Code of org.voltdb.utils.VoltTypeUtil

/* This file is part of VoltDB.
* Copyright (C) 2008-2010 VoltDB L.L.C.
*
* VoltDB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* VoltDB 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with VoltDB.  If not, see <http://www.gnu.org/licenses/>.
*/

package org.voltdb.utils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.voltdb.VoltType;
import org.voltdb.VoltTypeException;
import org.voltdb.types.TimestampType;

public abstract class VoltTypeUtil {
    private static final Logger LOG = Logger.getLogger(VoltTypeUtil.class.getName());

    protected final static Random rand = new Random();
    protected static final Integer DATE_STOP = Math.round(System.currentTimeMillis() / 1000);
    protected static final Integer DATE_START = VoltTypeUtil.DATE_STOP - 153792000;
   
    public static final String DATE_FORMAT_PATTERNS[] = {
        TimestampType.STRING_FORMAT,
        "EEE MMM dd HH:mm:ss zzz yyyy",     // Wed Aug 03 00:00:00 EDT 2011
        "yyyy-MM-dd HH:mm:ss",              // 2010-03-05 20:14:15
        "yyyy-MM-dd",                       // 2010-03-05
        TimestampType.STRING_FORMAT + ".0", // 2010-03-05T20:14:16.000.0
    };
    private static final Map<Thread, SimpleDateFormat[]> CACHED_DATE_FORMATS = new HashMap<Thread, SimpleDateFormat[]>();

    public static Object getRandomValue(VoltType type) {
        return getRandomValue(type, VoltTypeUtil.rand);
    }
   
    public static Object getRandomValue(VoltType type, Random rand) {
        Object ret = null;
        switch (type) {
            // --------------------------------
            // INTEGERS
            // --------------------------------
            case TINYINT:
                ret = Integer.valueOf((byte) Math.abs(rand.nextInt() % 128));
                break;
            case SMALLINT:
                ret = Integer.valueOf((short) Math.abs(rand.nextInt() % 32768));
                break;
            case INTEGER:
                ret = Integer.valueOf(Math.abs(rand.nextInt() % 100000));
                break;
            case BIGINT:
                ret = Long.valueOf(Math.abs(rand.nextInt() % 100000));
                break;
            // --------------------------------
            // FLOATS
            // --------------------------------
            case FLOAT:
            case DECIMAL:
                ret = Double.valueOf(Math.abs(rand.nextDouble()));
                break;
            // --------------------------------
            // STRINGS
            // --------------------------------
            case STRING:
                //int size = rand.nextInt(31) + 1;
                int size = 124;
                String ret_str = "";
                for (int ctr = 0; ctr < size; ctr++) {
                    char data = (char)(Math.abs(rand.nextInt()) % 128);
                    //
                    // Skip quotation marks
                    //
                    if (Character.isLetter(data) == false) {
                       ctr--;
                    } else {
                       ret_str += String.valueOf(data);
                    }
                 }
                ret = ret_str;
                break;
            // --------------------------------
            // TIMESTAMP
            // --------------------------------
            case TIMESTAMP: {
                int timestamp = rand.nextInt(VoltTypeUtil.DATE_STOP - VoltTypeUtil.DATE_START) + VoltTypeUtil.DATE_START;
                ret = new TimestampType(Long.valueOf(timestamp * 1000));
                break;
            }
            // --------------------------------
            // INVALID
            // --------------------------------
            default:
                LOG.severe("ERROR: Unable to generate random value for invalid ValueType '" + type + "'");
        } // SWITCH
        return (ret);
    }

    /*
     * Determine if a cast is allowable w/o loss of precision
     * for index key comparison. This is probably overly strict.
     */
    public static boolean isAllowableCastForKeyComparator(VoltType from, VoltType to) {
        // self to self cast is obviously fine.
        if (from == to)
            return true;

        // allow only float to float
        // allow only decimal to decimal
        // allow only string to string
        if (to == VoltType.STRING    ||
            from == VoltType.STRING  ||
            to == VoltType.DECIMAL   ||
            from == VoltType.DECIMAL ||
            to == VoltType.FLOAT     ||
            from == VoltType.FLOAT)
        {
            return from == to;
        }

        // disallow integers getting smaller
        if (from == VoltType.BIGINT) {
            if (to == VoltType.SMALLINT ||
                to == VoltType.TINYINT  ||
                to == VoltType.INTEGER)
                return false;
        }
        else if (from == VoltType.INTEGER) {
            if (to == VoltType.SMALLINT ||
                to == VoltType.TINYINT)
                return false;
        }
        else if (from == VoltType.SMALLINT) {
            if (to == VoltType.TINYINT)
                return false;
        }

        return true;
    }

    public static VoltType determineImplicitCasting(VoltType left, VoltType right) {
        //
        // Make sure both are valid
        //
        if (left == VoltType.INVALID || right == VoltType.INVALID) {
            throw new VoltTypeException("ERROR: Unable to determine cast type for '" + left + "' and '" + right + "' types");
        }
        // Check for NULL first, if either type is NULL the output is always NULL
        // XXX do we need to actually check for all NULL_foo types here?
        else if (left == VoltType.NULL || right == VoltType.NULL)
        {
            return VoltType.NULL;
        }
        //
        // No mixing of strings and numbers
        //
        else if ((left == VoltType.STRING && right != VoltType.STRING) ||
                (left != VoltType.STRING && right == VoltType.STRING))
        {
            throw new VoltTypeException("ERROR: Unable to determine cast type for '" +
                                        left + "' and '" + right + "' types");
        }

        // Allow promoting INTEGER types to DECIMAL.
        else if ((left == VoltType.DECIMAL || right == VoltType.DECIMAL) &&
                !(left.isExactNumeric() && right.isExactNumeric()))
        {
            throw new VoltTypeException("ERROR: Unable to determine cast type for '" +
                                        left + "' and '" + right + "' types");
        }
        //
        // The following list contains the rules that use for casting:
        //
        //    (1) If both types are a STRING, the output is always a STRING
        //        Note that up above we made sure that they do not mix strings and numbers
        //            Example: STRING + STRING -> STRING
        //    (2) If one type is a DECIMAL, the output is always a DECIMAL
        //        Note that above we made sure that DECIMAL only mixes with
        //        allowed types
        //    (3) Floating-point types take precedence over integers
        //            Example: FLOAT + INTEGER -> FLOAT
        //    (4) Specific types for floating-point and integer types take precedence
        //        over the more general types
        //            Example: MONEY + FLOAT -> MONEY
        //            Example: TIMESTAMP + INTEGER -> TIMESTAMP
        VoltType cast_order[] = { VoltType.STRING,
                                  VoltType.DECIMAL,
                                  VoltType.FLOAT,
                                  VoltType.TIMESTAMP,
                                  VoltType.BIGINT };
        for (VoltType cast_type : cast_order) {
            //
            // If any one of the types is the current cast type, we'll use that
            //
            if (left == cast_type || right == cast_type)
            {
                return cast_type;
            }
        }

        // If we have INT types smaller than BIGINT
        // promote the output up to BIGINT
        if ((left == VoltType.INTEGER || left == VoltType.SMALLINT || left == VoltType.TINYINT) &&
                (right == VoltType.INTEGER || right == VoltType.SMALLINT || right == VoltType.TINYINT))
        {
            return VoltType.BIGINT;
        }

        // If we get here, we couldn't figure out what to do
        throw new VoltTypeException("ERROR: Unable to determine cast type for '" +
                                    left + "' and '" + right + "' types");
    }

    /**
     * Some of our workloads (like TPC-E) will have commands and other crap in the #s that we need to strip out
     * @param value
     * @return
     */
    private static String cleanNumberString(String value) {
        Matcher m = pattern_cleanNumberString.matcher(value);
        return (m.replaceAll(""));
    }
    private static final Pattern pattern_cleanNumberString = Pattern.compile("[,)]");
   
    /**
     * Returns a casted object of the input value string based on the given type
     * @throws ParseException
     */
    public static Object getObjectFromString(VoltType type, String value) throws ParseException {
        return (VoltTypeUtil.getObjectFromString(type, value, Thread.currentThread()));
    }
       
    /**
     * Returns a casted object of the input value string based on the given type
     * You can pass the current thread to get a faster access for the cached SimpleDateFormats
     * @param type
     * @param value
     * @param self
     * @return
     * @throws ParseException
     */
    public static Object getObjectFromString(VoltType type, String value, Thread self) throws ParseException {
        Object ret = null;
        switch (type) {
            // NOTE: All runtime integer parameters are actually Longs,so we will have problems
            // if we actually try to convert the object to one of the smaller numeric sizes

            // --------------------------------
            // INTEGERS
            // --------------------------------
            case TINYINT:
                //ret = Byte.valueOf(value);
                //break;
            case SMALLINT:
                //ret = Short.valueOf(value);
                //break;
            case INTEGER:
                ret = Integer.valueOf(value);
                break;
            case BIGINT:
                try {
                    ret = Long.valueOf(value);
                } catch (NumberFormatException ex) {
                    ret = Long.valueOf(cleanNumberString(value));
                }
                break;
            // --------------------------------
            // FLOATS
            // --------------------------------
            case FLOAT:
            case DECIMAL:
                try {
                    ret = Double.valueOf(value);
                } catch (NumberFormatException ex) {
                    ret = Double.valueOf(cleanNumberString(value));
                }
                break;
            // --------------------------------
            // STRINGS
            // --------------------------------
            case STRING:
                ret = value;
                break;
            // --------------------------------
            // TIMESTAMP
            // --------------------------------
            case TIMESTAMP: {
                Date date = null;
                int usecs = 0;
                if (value.isEmpty()) throw new RuntimeException("Empty " + type + " parameter value");
               
                // We have to do this because apparently SimpleDateFormat isn't thread safe
                SimpleDateFormat formats[] = VoltTypeUtil.CACHED_DATE_FORMATS.get(self);
                if (formats == null) {
                    formats = new SimpleDateFormat[VoltTypeUtil.DATE_FORMAT_PATTERNS.length];
                    for (int i = 0; i < formats.length; i++) {
                        formats[i] = new SimpleDateFormat(VoltTypeUtil.DATE_FORMAT_PATTERNS[i]);
                    } // FOR
                    VoltTypeUtil.CACHED_DATE_FORMATS.put(self, formats);
                }
               
                ParseException last_ex = null;
                for (int i = 0; i < formats.length; i++) {
                    try {
                        date = formats[i].parse(value);
                        // We need to get the last microseconds
                        if (i == 0) usecs = Integer.parseInt(value.substring(value.lastIndexOf('.')+1));
                    } catch (ParseException ex) {
                        last_ex = ex;
                    }
                    if (date != null) break;
                } // FOR
                if (date == null) throw last_ex;
                ret = new TimestampType((date.getTime() * 1000) + usecs);
                break;
            }
            // --------------------------------
            // BOOLEAN
            // --------------------------------
            case BOOLEAN:
                ret = Boolean.parseBoolean(value);
                break;

            // --------------------------------
            // NULL
            // --------------------------------
            case NULL:
                ret = null;
                break;
            // --------------------------------
            // INVALID
            // --------------------------------
            default: {
                String msg = "Unable to get object for value with invalid ValueType '" + type + "'";
                throw new ParseException(msg, 0);
                // LOG.severe(msg);
            }
        }
        return (ret);
    }
   
    public static Object getPrimitiveArray(VoltType type, Object objArray[]) {
        Object ret = null;
        switch (type) {
            // --------------------------------
            // INTEGERS
            // --------------------------------
            case TINYINT: {
                Byte valArray[] = new Byte[objArray.length];
                for (int i = 0; i < objArray.length; i++) {
                    valArray[i] = ((Integer)objArray[i]).byteValue();
                } // FOR
                ret = valArray;
                break;
            }
            case SMALLINT: {
                Short valArray[] = new Short[objArray.length];
                for (int i = 0; i < objArray.length; i++) {
                    valArray[i] = ((Integer)objArray[i]).shortValue();
                } // FOR
                ret = valArray;
                break;
            }
            case INTEGER: {
                Integer valArray[] = new Integer[objArray.length];
                for (int i = 0; i < objArray.length; i++) {
                    valArray[i] = (Integer)objArray[i];
                } // FOR
                ret = valArray;
                break;
            }
            case BIGINT: {
                Long valArray[] = new Long[objArray.length];
                for (int i = 0; i < objArray.length; i++) {
                    valArray[i] = (Long)objArray[i];
                } // FOR
                ret = valArray;
                break;
            }
            // --------------------------------
            // FLOATS
            // --------------------------------
            case FLOAT:
            case DECIMAL: {
                Double valArray[] = new Double[objArray.length];
                for (int i = 0; i < objArray.length; i++) {
                    valArray[i] = (Double)objArray[i];
                } // FOR
                ret = valArray;
                break;
            }
            // --------------------------------
            // STRINGS
            // --------------------------------
            case STRING: {
                String valArray[] = new String[objArray.length];
                for (int i = 0; i < objArray.length; i++) {
                    valArray[i] = (String)objArray[i];
                } // FOR
                ret = valArray;
                break;
            }
            // --------------------------------
            // TIMESTAMP
            // --------------------------------
            case TIMESTAMP: {
                TimestampType valArray[] = new TimestampType[objArray.length];
                for (int i = 0; i < objArray.length; i++) {
                    valArray[i] = (TimestampType)objArray[i];
                } // FOR
                ret = valArray;
                break;
            }
            // --------------------------------
            // BOOLEAN
            // --------------------------------
            case BOOLEAN: {
                Boolean valArray[] = new Boolean[objArray.length];
                for (int i = 0; i < objArray.length; i++) {
                    valArray[i] = (Boolean)objArray[i];
                } // FOR
                ret = valArray;
                break;
            }
            // --------------------------------
            // NULL
            // --------------------------------
            case NULL:
                ret = null;
                break;
            // --------------------------------
            // INVALID
            // --------------------------------
            default: {
                String msg = "Unable to get object for value with invalid ValueType '" + type + "'";
                throw new RuntimeException(msg);
            }
        } // SWITCH
        return (ret);
    }
}
TOP

Related Classes of org.voltdb.utils.VoltTypeUtil

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.