/** * 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.hadoop.hive.ql.udf.generic; import java.sql.Date; import org.apache.hadoop.hive.ql.exec.Description; import org.apache.hadoop.hive.serde2.io.ShortWritable; import org.apache.hadoop.hive.serde2.objectinspector.ConstantObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.primitive.*; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.LongWritable; @Description(name = "mask", value = "masks the given value", extended = "Examples:\n " + " mask(ccn)\n " + " mask(ccn, 'X', 'x', '0')\n " + " mask(ccn, 'x', 'x', 'x')\n " + "Arguments:\n " + " mask(value, upperChar, lowerChar, digitChar, otherChar, numberChar, dayValue, monthValue, yearValue)\n " + " value - value to mask. Supported types: TINYINT, SMALLINT, INT, BIGINT, STRING, VARCHAR, CHAR, DATE\n " + " upperChar - character to replace upper-case characters with. Specify -1 to retain original character. Default value: 'X'\n " + " lowerChar - character to replace lower-case characters with. Specify -1 to retain original character. Default value: 'x'\n " + " digitChar - character to replace digit characters with. Specify -1 to retain original character. Default value: 'n'\n " + " otherChar - character to replace all other characters with. Specify -1 to retain original character. Default value: -1\n " + " numberChar - character to replace digits in a number with. Valid values: 0-9. Default value: '1'\n " + " dayValue - value to replace day field in a date with. Specify -1 to retain original value. Valid values: 1-31. Default value: 1\n " + " monthValue - value to replace month field in a date with. Specify -1 to retain original value. Valid values: 0-11. Default value: 0\n " + " yearValue - value to replace year field in a date with. Specify -1 to retain original value. Default value: 0\n " ) public class GenericUDFMask extends BaseMaskUDF { public static final String UDF_NAME = "mask"; public GenericUDFMask() { super(new MaskTransformer(), UDF_NAME); } } class MaskTransformer extends AbstractTransformer { final static int MASKED_UPPERCASE = 'X'; final static int MASKED_LOWERCASE = 'x'; final static int MASKED_DIGIT = 'n'; final static int MASKED_OTHER_CHAR = -1; final static int MASKED_NUMBER = 1; final static int MASKED_DAY_COMPONENT_VAL = 1; final static int MASKED_MONTH_COMPONENT_VAL = 0; final static int MASKED_YEAR_COMPONENT_VAL = 0; final static int UNMASKED_VAL = -1; int maskedUpperChar = MASKED_UPPERCASE; int maskedLowerChar = MASKED_LOWERCASE; int maskedDigitChar = MASKED_DIGIT; int maskedOtherChar = MASKED_OTHER_CHAR; int maskedNumber = MASKED_NUMBER; int maskedDayValue = MASKED_DAY_COMPONENT_VAL; int maskedMonthValue = MASKED_MONTH_COMPONENT_VAL; int maskedYearValue = MASKED_YEAR_COMPONENT_VAL; public MaskTransformer() { } @Override public void init(ObjectInspector[] arguments, int startIdx) { int idx = startIdx; maskedUpperChar = getCharArg(arguments, idx++, MASKED_UPPERCASE); maskedLowerChar = getCharArg(arguments, idx++, MASKED_LOWERCASE); maskedDigitChar = getCharArg(arguments, idx++, MASKED_DIGIT); maskedOtherChar = getCharArg(arguments, idx++, MASKED_OTHER_CHAR); maskedNumber = getIntArg(arguments, idx++, MASKED_NUMBER); maskedDayValue = getIntArg(arguments, idx++, MASKED_DAY_COMPONENT_VAL); maskedMonthValue = getIntArg(arguments, idx++, MASKED_MONTH_COMPONENT_VAL); maskedYearValue = getIntArg(arguments, idx++, MASKED_YEAR_COMPONENT_VAL); if(maskedNumber < 0 || maskedNumber > 9) { maskedNumber = MASKED_NUMBER; } if(maskedDayValue != UNMASKED_VAL) { if(maskedDayValue < 1 || maskedDayValue > 31) { maskedDayValue = MASKED_DAY_COMPONENT_VAL; } } if(maskedMonthValue != UNMASKED_VAL) { if(maskedMonthValue < 0 || maskedMonthValue > 11) { maskedMonthValue = MASKED_MONTH_COMPONENT_VAL; } } } @Override String transform(final String val) { StringBuilder ret = new StringBuilder(val.length()); for(int i = 0; i < val.length(); i++) { ret.appendCodePoint(transformChar(val.charAt(i))); } return ret.toString(); } @Override Byte transform(final Byte value) { byte val = value; if(value < 0) { val *= -1; } byte ret = 0; int pos = 1; while(val != 0) { ret += maskedNumber * pos; val /= 10; pos *= 10; } if(value < 0) { ret *= -1; } return ret; } @Override Short transform(final Short value) { short val = value; if(value < 0) { val *= -1; } short ret = 0; int pos = 1; while(val != 0) { ret += maskedNumber * pos; val /= 10; pos *= 10; } if(value < 0) { ret *= -1; } return ret; } @Override Integer transform(final Integer value) { int val = value; if(value < 0) { val *= -1; } int ret = 0; int pos = 1; while(val != 0) { ret += maskedNumber * pos; val /= 10; pos *= 10; } if(value < 0) { ret *= -1; } return ret; } @Override Long transform(final Long value) { long val = value; if(value < 0) { val *= -1; } long ret = 0; long pos = 1; for(int i = 0; val != 0; i++) { ret += maskedNumber * pos; val /= 10; pos *= 10; } if(value < 0) { ret *= -1; } return ret; } @Override Date transform(final Date value) { int year = maskedYearValue == UNMASKED_VAL ? value.getYear() : maskedYearValue; int month = maskedMonthValue == UNMASKED_VAL ? value.getMonth() : maskedMonthValue; int day = maskedDayValue == UNMASKED_VAL ? value.getDate() : maskedDayValue; return new Date(year, month, day); } protected int transformChar(final int c) { switch(Character.getType(c)) { case Character.UPPERCASE_LETTER: if(maskedUpperChar != UNMASKED_VAL) { return maskedUpperChar; } break; case Character.LOWERCASE_LETTER: if(maskedLowerChar != UNMASKED_VAL) { return maskedLowerChar; } break; case Character.DECIMAL_DIGIT_NUMBER: if(maskedDigitChar != UNMASKED_VAL) { return maskedDigitChar; } break; default: if(maskedOtherChar != UNMASKED_VAL) { return maskedOtherChar; } break; } return c; } int getCharArg(ObjectInspector[] arguments, int index, int defaultValue) { int ret = defaultValue; ObjectInspector arg = (arguments != null && arguments.length > index) ? arguments[index] : null; if (arg != null) { if(arg instanceof WritableConstantIntObjectInspector) { IntWritable value = ((WritableConstantIntObjectInspector)arg).getWritableConstantValue(); if(value != null) { ret = value.get(); } } else if(arg instanceof WritableConstantLongObjectInspector) { LongWritable value = ((WritableConstantLongObjectInspector)arg).getWritableConstantValue(); if(value != null) { ret = (int)value.get(); } } else if(arg instanceof WritableConstantShortObjectInspector) { ShortWritable value = ((WritableConstantShortObjectInspector)arg).getWritableConstantValue(); if(value != null) { ret = value.get(); } } else if(arg instanceof ConstantObjectInspector) { Object value = ((ConstantObjectInspector) arg).getWritableConstantValue(); if (value != null) { String strValue = value.toString(); if (strValue != null && strValue.length() > 0) { ret = strValue.charAt(0); } } } } return ret; } int getIntArg(ObjectInspector[] arguments, int index, int defaultValue) { int ret = defaultValue; ObjectInspector arg = (arguments != null && arguments.length > index) ? arguments[index] : null; if (arg != null) { if (arg instanceof WritableConstantIntObjectInspector) { IntWritable value = ((WritableConstantIntObjectInspector) arg).getWritableConstantValue(); if (value != null) { ret = value.get(); } } else if (arg instanceof WritableConstantLongObjectInspector) { LongWritable value = ((WritableConstantLongObjectInspector) arg).getWritableConstantValue(); if (value != null) { ret = (int) value.get(); } } else if (arg instanceof WritableConstantShortObjectInspector) { ShortWritable value = ((WritableConstantShortObjectInspector) arg).getWritableConstantValue(); if (value != null) { ret = value.get(); } } else if (arg instanceof ConstantObjectInspector) { Object value = ((ConstantObjectInspector) arg).getWritableConstantValue(); if (value != null) { String strValue = value.toString(); if (strValue != null && strValue.length() > 0) { ret = Integer.parseInt(value.toString()); } } } } return ret; } }