From 20df950ffd735eaca3924f8ba2f0279a8c17f81c Mon Sep 17 00:00:00 2001 From: Madhan Neethiraj Date: Wed, 20 Apr 2016 23:57:55 -0700 Subject: [PATCH] HIVE-13568: added UDFs for use in column-masking --- .../hadoop/hive/ql/exec/FunctionRegistry.java | 8 + .../hadoop/hive/ql/udf/generic/BaseMaskUDF.java | 408 +++++++++++++++++++++ .../hadoop/hive/ql/udf/generic/GenericUDFMask.java | 342 +++++++++++++++++ .../hive/ql/udf/generic/GenericUDFMaskFirstN.java | 92 +++++ .../hive/ql/udf/generic/GenericUDFMaskHash.java | 75 ++++ .../hive/ql/udf/generic/GenericUDFMaskLastN.java | 92 +++++ .../ql/udf/generic/GenericUDFMaskShowFirstN.java | 92 +++++ .../ql/udf/generic/GenericUDFMaskShowLastN.java | 92 +++++ ql/src/test/queries/clientpositive/udf_mask.q | 13 + .../test/queries/clientpositive/udf_mask_first_n.q | 13 + ql/src/test/queries/clientpositive/udf_mask_hash.q | 13 + .../test/queries/clientpositive/udf_mask_last_n.q | 13 + .../queries/clientpositive/udf_mask_show_first_n.q | 13 + .../queries/clientpositive/udf_mask_show_last_n.q | 13 + 14 files changed, 1279 insertions(+) create mode 100644 ql/src/java/org/apache/hadoop/hive/ql/udf/generic/BaseMaskUDF.java create mode 100644 ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFMask.java create mode 100644 ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFMaskFirstN.java create mode 100644 ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFMaskHash.java create mode 100644 ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFMaskLastN.java create mode 100644 ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFMaskShowFirstN.java create mode 100644 ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFMaskShowLastN.java create mode 100644 ql/src/test/queries/clientpositive/udf_mask.q create mode 100644 ql/src/test/queries/clientpositive/udf_mask_first_n.q create mode 100644 ql/src/test/queries/clientpositive/udf_mask_hash.q create mode 100644 ql/src/test/queries/clientpositive/udf_mask_last_n.q create mode 100644 ql/src/test/queries/clientpositive/udf_mask_show_first_n.q create mode 100644 ql/src/test/queries/clientpositive/udf_mask_show_last_n.q diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java b/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java index 1343b39..e813e6f 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/FunctionRegistry.java @@ -474,6 +474,14 @@ system.registerHiddenBuiltIn(GenericUDFOPDTIPlus.class); system.registerHiddenBuiltIn(GenericUDFOPNumericMinus.class); system.registerHiddenBuiltIn(GenericUDFOPNumericPlus.class); + + // mask UDFs + system.registerGenericUDF("mask", GenericUDFMask.class); + system.registerGenericUDF("mask_first_n", GenericUDFMaskFirstN.class); + system.registerGenericUDF("mask_last_n", GenericUDFMaskLastN.class); + system.registerGenericUDF("mask_show_first_n", GenericUDFMaskShowFirstN.class); + system.registerGenericUDF("mask_show_last_n", GenericUDFMaskShowLastN.class); + system.registerGenericUDF("mask_hash", GenericUDFMaskHash.class); } public static String getNormalizedFunctionName(String fn) throws SemanticException { diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/BaseMaskUDF.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/BaseMaskUDF.java new file mode 100644 index 0000000..0eeca5a --- /dev/null +++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/BaseMaskUDF.java @@ -0,0 +1,408 @@ +/** + * 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 org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.hive.common.type.HiveChar; +import org.apache.hadoop.hive.common.type.HiveVarchar; +import org.apache.hadoop.hive.ql.exec.UDFArgumentException; +import org.apache.hadoop.hive.ql.metadata.HiveException; +import org.apache.hadoop.hive.ql.udf.generic.GenericUDF.DeferredObject; +import org.apache.hadoop.hive.serde2.io.*; +import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector; +import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector; +import org.apache.hadoop.hive.serde2.objectinspector.primitive.*; +import org.apache.hadoop.io.IntWritable; +import org.apache.hadoop.io.LongWritable; +import org.apache.hadoop.io.Text; + +import java.sql.Date; + + +public abstract class BaseMaskUDF extends GenericUDF { + private static final Log LOG = LogFactory.getLog(BaseMaskUDF.class); + + final protected BaseMaskUDF.AbstractTransformer transformer; + protected AbstractTransformerAdapter transformerAdapter = null; + + protected BaseMaskUDF(BaseMaskUDF.AbstractTransformer transformer) { + this.transformer = transformer; + } + + public ObjectInspector initialize(ObjectInspector[] arguments) throws UDFArgumentException { + LOG.debug("==> BaseMaskUDF.initialize()"); + + checkArgPrimitive(arguments, 0); // first argument is the column to be transformed + + PrimitiveObjectInspector columnType = ((PrimitiveObjectInspector) arguments[0]); + + transformer.init(arguments, 1); + + transformerAdapter = AbstractTransformerAdapter.getTransformerAdapter(columnType, transformer); + + ObjectInspector ret = PrimitiveObjectInspectorFactory.getPrimitiveWritableObjectInspector(columnType.getPrimitiveCategory()); + + LOG.debug("<== BaseMaskUDF.initialize()"); + + return ret; + } + + @Override + public Object evaluate(DeferredObject[] arguments) throws HiveException { + Object ret = transformerAdapter.getTransformedWritable(arguments[0]); + + return ret; + } + + @Override + public String getDisplayString(String[] children) { + return getStandardDisplayString(getClass().getName(), children, ","); + } + + static abstract class AbstractTransformer { + abstract void init(ObjectInspector[] arguments, int startIdx); + + abstract String transform(String value); + abstract Byte transform(Byte value); + abstract Short transform(Short value); + abstract Integer transform(Integer value); + abstract Long transform(Long value); + abstract Date transform(Date value); + } +} + + +abstract class AbstractTransformerAdapter { + final BaseMaskUDF.AbstractTransformer transformer; + + AbstractTransformerAdapter(BaseMaskUDF.AbstractTransformer transformer) { + this.transformer = transformer; + } + + abstract Object getTransformedWritable(DeferredObject value) throws HiveException; + + static AbstractTransformerAdapter getTransformerAdapter(PrimitiveObjectInspector columnType, BaseMaskUDF.AbstractTransformer transformer) { + final AbstractTransformerAdapter ret; + + switch(columnType.getPrimitiveCategory()) { + case STRING: + ret = new StringTransformerAdapter((StringObjectInspector)columnType, transformer); + break; + + case CHAR: + ret = new HiveCharTransformerAdapter((HiveCharObjectInspector)columnType, transformer); + break; + + case VARCHAR: + ret = new HiveVarcharTransformerAdapter((HiveVarcharObjectInspector)columnType, transformer); + break; + + case BYTE: + ret = new ByteTransformerAdapter((ByteObjectInspector)columnType, transformer); + break; + + case SHORT: + ret = new ShortTransformerAdapter((ShortObjectInspector)columnType, transformer); + break; + + case INT: + ret = new IntegerTransformerAdapter((IntObjectInspector)columnType, transformer); + break; + + case LONG: + ret = new LongTransformerAdapter((LongObjectInspector)columnType, transformer); + break; + + case DATE: + ret = new DateTransformerAdapter((DateObjectInspector)columnType, transformer); + break; + + default: + ret = new NoTransformAdapter(columnType, transformer); + break; + } + + return ret; + } +} + +class ByteTransformerAdapter extends AbstractTransformerAdapter { + final ByteObjectInspector columnType; + final ByteWritable writable; + + public ByteTransformerAdapter(ByteObjectInspector columnType, BaseMaskUDF.AbstractTransformer transformer) { + this(columnType, transformer, new ByteWritable()); + } + + public ByteTransformerAdapter(ByteObjectInspector columnType, BaseMaskUDF.AbstractTransformer transformer, ByteWritable writable) { + super(transformer); + + this.columnType = columnType; + this.writable = writable; + } + + @Override + public Object getTransformedWritable(DeferredObject object) throws HiveException { + Byte value = (Byte)columnType.getPrimitiveJavaObject(object.get()); + + if(value != null) { + Byte transformedValue = transformer.transform(value); + + writable.set(transformedValue); + + return writable; + } + + return null; + } +} + +class DateTransformerAdapter extends AbstractTransformerAdapter { + final DateObjectInspector columnType; + final DateWritable writable; + + public DateTransformerAdapter(DateObjectInspector columnType, BaseMaskUDF.AbstractTransformer transformer) { + this(columnType, transformer, new DateWritable()); + } + + public DateTransformerAdapter(DateObjectInspector columnType, BaseMaskUDF.AbstractTransformer transformer, DateWritable writable) { + super(transformer); + + this.columnType = columnType; + this.writable = writable; + } + + @Override + public Object getTransformedWritable(DeferredObject object) throws HiveException { + Date value = columnType.getPrimitiveJavaObject(object.get()); + + if(value != null) { + Date transformedValue = transformer.transform(value); + + writable.set(transformedValue); + + return writable; + } + + return null; + } +} + +class HiveCharTransformerAdapter extends AbstractTransformerAdapter { + final HiveCharObjectInspector columnType; + final HiveCharWritable writable; + + public HiveCharTransformerAdapter(HiveCharObjectInspector columnType, BaseMaskUDF.AbstractTransformer transformer) { + this(columnType, transformer, new HiveCharWritable()); + } + + public HiveCharTransformerAdapter(HiveCharObjectInspector columnType, BaseMaskUDF.AbstractTransformer transformer, HiveCharWritable writable) { + super(transformer); + + this.columnType = columnType; + this.writable = writable; + } + + @Override + public Object getTransformedWritable(DeferredObject object) throws HiveException { + HiveChar value = columnType.getPrimitiveJavaObject(object.get()); + + if(value != null) { + String transformedValue = transformer.transform(value.getValue()); + + writable.set(transformedValue); + + return writable; + } + + return null; + } +} + +class HiveVarcharTransformerAdapter extends AbstractTransformerAdapter { + final HiveVarcharObjectInspector columnType; + final HiveVarcharWritable writable; + + public HiveVarcharTransformerAdapter(HiveVarcharObjectInspector columnType, BaseMaskUDF.AbstractTransformer transformer) { + this(columnType, transformer, new HiveVarcharWritable()); + } + + public HiveVarcharTransformerAdapter(HiveVarcharObjectInspector columnType, BaseMaskUDF.AbstractTransformer transformer, HiveVarcharWritable writable) { + super(transformer); + + this.columnType = columnType; + this.writable = writable; + } + + @Override + public Object getTransformedWritable(DeferredObject object) throws HiveException { + HiveVarchar value = columnType.getPrimitiveJavaObject(object.get()); + + if(value != null) { + String transformedValue = transformer.transform(value.getValue()); + + writable.set(transformedValue); + + return writable; + } + + return null; + } +} + +class IntegerTransformerAdapter extends AbstractTransformerAdapter { + final IntObjectInspector columnType; + final IntWritable writable; + + public IntegerTransformerAdapter(IntObjectInspector columnType, BaseMaskUDF.AbstractTransformer transformer) { + this(columnType, transformer, new IntWritable()); + } + + public IntegerTransformerAdapter(IntObjectInspector columnType, BaseMaskUDF.AbstractTransformer transformer, IntWritable writable) { + super(transformer); + + this.columnType = columnType; + this.writable = writable; + } + + @Override + public Object getTransformedWritable(DeferredObject object) throws HiveException { + Integer value = (Integer)columnType.getPrimitiveJavaObject(object.get()); + + if(value != null) { + Integer transformedValue = transformer.transform(value); + + writable.set(transformedValue); + + return writable; + } + + return null; + } +} + +class LongTransformerAdapter extends AbstractTransformerAdapter { + final LongObjectInspector columnType; + final LongWritable writable; + + public LongTransformerAdapter(LongObjectInspector columnType, BaseMaskUDF.AbstractTransformer transformer) { + this(columnType, transformer, new LongWritable()); + } + + public LongTransformerAdapter(LongObjectInspector columnType, BaseMaskUDF.AbstractTransformer transformer, LongWritable writable) { + super(transformer); + + this.columnType = columnType; + this.writable = writable; + } + + @Override + public Object getTransformedWritable(DeferredObject object) throws HiveException { + Long value = (Long)columnType.getPrimitiveJavaObject(object.get()); + + if(value != null) { + Long transformedValue = transformer.transform(value); + + writable.set(transformedValue); + + return writable; + } + + return null; + } +} + +class NoTransformAdapter extends AbstractTransformerAdapter { + final PrimitiveObjectInspector columnType; + + public NoTransformAdapter(PrimitiveObjectInspector columnType, BaseMaskUDF.AbstractTransformer transformer) { + super(transformer); + + this.columnType = columnType; + } + + @Override + public Object getTransformedWritable(DeferredObject object) throws HiveException { + return columnType.getPrimitiveWritableObject(object.get()); + } +} + +class ShortTransformerAdapter extends AbstractTransformerAdapter { + final ShortObjectInspector columnType; + final ShortWritable writable; + + public ShortTransformerAdapter(ShortObjectInspector columnType, BaseMaskUDF.AbstractTransformer transformer) { + this(columnType, transformer, new ShortWritable()); + } + + public ShortTransformerAdapter(ShortObjectInspector columnType, BaseMaskUDF.AbstractTransformer transformer, ShortWritable writable) { + super(transformer); + + this.columnType = columnType; + this.writable = writable; + } + + @Override + public Object getTransformedWritable(DeferredObject object) throws HiveException { + Short value = (Short)columnType.getPrimitiveJavaObject(object.get()); + + if(value != null) { + Short transformedValue = transformer.transform(value); + + writable.set(transformedValue); + + return writable; + } + + return null; + } +} + +class StringTransformerAdapter extends AbstractTransformerAdapter { + final StringObjectInspector columnType; + final Text writable; + + public StringTransformerAdapter(StringObjectInspector columnType, BaseMaskUDF.AbstractTransformer transformer) { + this(columnType, transformer, new Text()); + } + + public StringTransformerAdapter(StringObjectInspector columnType, BaseMaskUDF.AbstractTransformer transformer, Text writable) { + super(transformer); + + this.columnType = columnType; + this.writable = writable; + } + + @Override + public Object getTransformedWritable(DeferredObject object) throws HiveException { + String value = columnType.getPrimitiveJavaObject(object.get()); + + if(value != null) { + String transformedValue = transformer.transform(value); + + writable.set(transformedValue); + + return writable; + } + + return null; + } +} diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFMask.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFMask.java new file mode 100644 index 0000000..214590e --- /dev/null +++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFMask.java @@ -0,0 +1,342 @@ +/** + * 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: '1'\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. Specify -1 to retain original character. 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 GenericUDFMask() { + super(new MaskTransformer()); + } +} + +class MaskTransformer extends BaseMaskUDF.AbstractTransformer { + final static int MASKED_UPPERCASE = 'X'; + final static int MASKED_LOWERCASE = 'x'; + final static int MASKED_NUMBER = '1'; + final static int MASKED_OTHER_CHAR = -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_NUMBER; + 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_NUMBER); + maskedOtherChar = getCharArg(arguments, idx++, MASKED_OTHER_CHAR); + maskedNumber = getCharArg(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); + } + + @Override + String transform(String value) { + return maskString(value, 0, value.length()); + } + + @Override + Byte transform(Byte value) { + String strValue = value.toString(); + + return toByte(Long.parseLong(maskNumber(strValue, 0, strValue.length()))); + } + + @Override + Short transform(Short value) { + String strValue = value.toString(); + + return toShort(Long.parseLong(maskNumber(strValue, 0, strValue.length()))); + } + + @Override + Integer transform(Integer value) { + String strValue = value.toString(); + + return toInteger(Long.parseLong(maskNumber(strValue, 0, strValue.length()))); + } + + @Override + Long transform(Long value) { + String strValue = value.toString(); + + return Long.parseLong(maskNumber(strValue, 0, strValue.length())); + } + + @Override + Date transform(Date value) { + return maskDate(value); + } + + + String maskString(String val, int startIdx, int endIdx) { + StringBuilder strBuf = new StringBuilder(val.length()); + + if(startIdx < 0) { + startIdx = 0; + } + + if(endIdx > val.length()) { + endIdx = val.length(); + } + + for(int i = 0; i < startIdx; i++) { + strBuf.appendCodePoint(val.charAt(i)); + } + + for(int i = startIdx; i < endIdx; i++) { + int c = val.charAt(i); + + switch(Character.getType(c)) { + case Character.UPPERCASE_LETTER: + if(maskedUpperChar != UNMASKED_VAL) { + c = maskedUpperChar; + } + break; + + case Character.LOWERCASE_LETTER: + if(maskedLowerChar != UNMASKED_VAL) { + c = maskedLowerChar; + } + break; + + case Character.DECIMAL_DIGIT_NUMBER: + if(maskedDigitChar != UNMASKED_VAL) { + c = maskedDigitChar; + } + break; + + default: + if(maskedOtherChar != UNMASKED_VAL) { + c = maskedOtherChar; + } + break; + } + + strBuf.appendCodePoint(c); + } + + for(int i = endIdx; i < val.length(); i++) { + strBuf.appendCodePoint(val.charAt(i)); + } + + return strBuf.toString(); + } + + String maskNumber(String val, int startIdx, int endIdx) { + if(maskedNumber != UNMASKED_VAL) { + StringBuilder strBuf = new StringBuilder(val.length()); + + if (startIdx < 0) { + startIdx = 0; + } + + if (endIdx > val.length()) { + endIdx = val.length(); + } + + for (int i = 0; i < startIdx; i++) { + strBuf.appendCodePoint(val.charAt(i)); + } + + for (int i = startIdx; i < endIdx; i++) { + int c = val.charAt(i); + + switch (Character.getType(c)) { + case Character.DECIMAL_DIGIT_NUMBER: + c = maskedNumber; + break; + } + + strBuf.appendCodePoint(c); + } + + for (int i = endIdx; i < val.length(); i++) { + strBuf.appendCodePoint(val.charAt(i)); + } + + return strBuf.toString(); + } + + return val; + } + + Date maskDate(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); + } + + Byte toByte(long value) { + if(value < Byte.MIN_VALUE) { + return Byte.MIN_VALUE; + } else if(value > Byte.MAX_VALUE) { + return Byte.MAX_VALUE; + } else { + return (byte)value; + } + } + + Short toShort(long value) { + if(value < Short.MIN_VALUE) { + return Short.MIN_VALUE; + } else if(value > Short.MAX_VALUE) { + return Short.MAX_VALUE; + } else { + return (short)value; + } + } + + Integer toInteger(long value) { + if(value < Integer.MIN_VALUE) { + return Integer.MIN_VALUE; + } else if(value > Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } else { + return (int)value; + } + } + + 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; + } +} + diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFMaskFirstN.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFMaskFirstN.java new file mode 100644 index 0000000..14e01f0 --- /dev/null +++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFMaskFirstN.java @@ -0,0 +1,92 @@ +/** + * 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 org.apache.hadoop.hive.ql.exec.Description; +import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector; + + +@Description(name = "mask_first_n", + value = "masks the first n characters of the value", + extended = "Examples:\n " + + " mask_first_n(ccn, 8)\n " + + " mask_first_n(ccn, 8, 'x', 'x', 'x')\n " + + "Arguments:\n " + + " mask(value, charCount, upperChar, lowerChar, digitChar, otherChar, numberChar)\n " + + " value - value to mask. Supported types: SMALLINT, INT, BIGINT, STRING, VARCHAR, DATE\n " + + " charCount - number of characters. Default value: 4\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: '1'\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. Specify -1 to retain original character. Default value: '1'\n " + ) +public class GenericUDFMaskFirstN extends BaseMaskUDF { + public GenericUDFMaskFirstN() { + super(new MaskFirstNTransformer()); + } +} + +class MaskFirstNTransformer extends MaskTransformer { + int charCount = 4; + + public MaskFirstNTransformer() { + super(); + } + + @Override + public void init(ObjectInspector[] arguments, int argsStartIdx) { + super.init(arguments, argsStartIdx + 1); // first argument is charCount, which is consumed in this method below + + charCount = getIntArg(arguments, argsStartIdx, 4); + } + + @Override + String transform(String value) { + return maskString(value, 0, charCount); + } + + @Override + Byte transform(Byte value) { + String strValue = value.toString(); + + return toByte(Long.parseLong(maskNumber(strValue, 0, charCount))); + } + + @Override + Short transform(Short value) { + String strValue = value.toString(); + + return toShort(Long.parseLong(maskNumber(strValue, 0, charCount))); + } + + @Override + Integer transform(Integer value) { + String strValue = value.toString(); + + return toInteger(Long.parseLong(maskNumber(strValue, 0, charCount))); + } + + @Override + Long transform(Long value) { + String strValue = value.toString(); + + return Long.parseLong(maskNumber(strValue, 0, charCount)); + } +} diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFMaskHash.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFMaskHash.java new file mode 100644 index 0000000..065047f --- /dev/null +++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFMaskHash.java @@ -0,0 +1,75 @@ +/** + * 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.commons.codec.digest.DigestUtils; +import org.apache.hadoop.hive.ql.exec.Description; +import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector; + + +@Description(name = "mask_hash", + value = "returns hash of the given value", + extended = "Examples:\n " + + " mask_hash(value)\n " + + "Arguments:\n " + + " value - value to mask. Supported types: STRING, VARCHAR" + ) +public class GenericUDFMaskHash extends BaseMaskUDF { + public GenericUDFMaskHash() { + super(new MaskHashTransformer()); + } +} + +class MaskHashTransformer extends BaseMaskUDF.AbstractTransformer { + @Override + public void init(ObjectInspector[] arguments, int startIdx) { + } + + @Override + String transform(String value) { + return DigestUtils.md5Hex(value); + } + + @Override + Byte transform(Byte value) { + return value; + } + + @Override + Short transform(Short value) { + return value; + } + + @Override + Integer transform(Integer value) { + return value; + } + + @Override + Long transform(Long value) { + return value; + } + + @Override + Date transform(Date value) { + return value; + } +} diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFMaskLastN.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFMaskLastN.java new file mode 100644 index 0000000..1d9a89b --- /dev/null +++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFMaskLastN.java @@ -0,0 +1,92 @@ +/** + * 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 org.apache.hadoop.hive.ql.exec.Description; +import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector; + + +@Description(name = "mask_last_n", + value = "masks the last n characters of the value", + extended = "Examples:\n " + + " mask_last_n(ccn, 8)\n " + + " mask_last_n(ccn, 8, 'x', 'x', 'x')\n " + + "Arguments:\n " + + " mask_last_n(value, charCount, upperChar, lowerChar, digitChar, otherChar, numberChar)\n " + + " value - value to mask. Supported types: SMALLINT, INT, BIGINT, STRING, VARCHAR\n " + + " charCount - number of characters. Default value: 4\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: '1'\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. Specify -1 to retain original character. Default value: '1'\n " + ) +public class GenericUDFMaskLastN extends BaseMaskUDF { + public GenericUDFMaskLastN() { + super(new MaskLastNTransformer()); + } +} + +class MaskLastNTransformer extends MaskTransformer { + int charCount = 4; + + public MaskLastNTransformer() { + super(); + } + + @Override + public void init(ObjectInspector[] arguments, int argsStartIdx) { + super.init(arguments, argsStartIdx + 1); // first argument is charCount, which is consumed in this method below + + charCount = getIntArg(arguments, argsStartIdx, 4); + } + + @Override + String transform(String value) { + return maskString(value, value.length() - charCount, value.length()); + } + + @Override + Byte transform(Byte value) { + String strValue = value.toString(); + + return toByte(Long.parseLong(maskNumber(strValue, strValue.length() - charCount, strValue.length()))); + } + + @Override + Short transform(Short value) { + String strValue = value.toString(); + + return toShort(Long.parseLong(maskNumber(strValue, strValue.length() - charCount, strValue.length()))); + } + + @Override + Integer transform(Integer value) { + String strValue = value.toString(); + + return toInteger(Long.parseLong(maskNumber(strValue, strValue.length() - charCount, strValue.length()))); + } + + @Override + Long transform(Long value) { + String strValue = value.toString(); + + return Long.parseLong(maskNumber(strValue, strValue.length() - charCount, strValue.length())); + } +} diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFMaskShowFirstN.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFMaskShowFirstN.java new file mode 100644 index 0000000..78c836b --- /dev/null +++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFMaskShowFirstN.java @@ -0,0 +1,92 @@ +/** + * 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 org.apache.hadoop.hive.ql.exec.Description; +import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector; + + +@Description(name = "mask_show_first_n", + value = "masks all but first n characters of the value", + extended = "Examples:\n " + + " mask_show_first_n(ccn, 8)\n " + + " mask_show_first_n(ccn, 8, 'x', 'x', 'x')\n " + + "Arguments:\n " + + " mask_show_first_n(value, charCount, upperChar, lowerChar, digitChar, otherChar, numberChar)\n " + + " value - value to mask. Supported types: SMALLINT, INT, BIGINT, STRING, VARCHAR\n " + + " charCount - number of characters. Default value: 4\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: '1'\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. Specify -1 to retain original character. Default value: '1'\n " + ) +public class GenericUDFMaskShowFirstN extends BaseMaskUDF { + public GenericUDFMaskShowFirstN() { + super(new MaskShowFirstNTransformer()); + } +} + +class MaskShowFirstNTransformer extends MaskTransformer { + int charCount = 4; + + public MaskShowFirstNTransformer() { + super(); + } + + @Override + public void init(ObjectInspector[] arguments, int argsStartIdx) { + super.init(arguments, argsStartIdx + 1); // first argument is charCount, which is consumed here + + charCount = getIntArg(arguments, argsStartIdx, 4); + } + + @Override + String transform(String value) { + return maskString(value, charCount, value.length()); + } + + @Override + Byte transform(Byte value) { + String strValue = value.toString(); + + return toByte(Long.parseLong(maskNumber(strValue, charCount, strValue.length()))); + } + + @Override + Short transform(Short value) { + String strValue = value.toString(); + + return toShort(Long.parseLong(maskNumber(strValue, charCount, strValue.length()))); + } + + @Override + Integer transform(Integer value) { + String strValue = value.toString(); + + return toInteger(Long.parseLong(maskNumber(strValue, charCount, strValue.length()))); + } + + @Override + Long transform(Long value) { + String strValue = value.toString(); + + return Long.parseLong(maskNumber(strValue, charCount, strValue.length())); + } +} diff --git a/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFMaskShowLastN.java b/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFMaskShowLastN.java new file mode 100644 index 0000000..dd588ee --- /dev/null +++ b/ql/src/java/org/apache/hadoop/hive/ql/udf/generic/GenericUDFMaskShowLastN.java @@ -0,0 +1,92 @@ +/** + * 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 org.apache.hadoop.hive.ql.exec.Description; +import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector; + + +@Description(name = "mask_show_last_n", + value = "masks all but last n characters of the value", + extended = "Examples:\n " + + " mask_show_last_n(ccn, 8)\n " + + " mask_show_last_n(ccn, 8, 'x', 'x', 'x')\n " + + "Arguments:\n " + + " mask_show_last_n(value, charCount, upperChar, lowerChar, digitChar, otherChar, numberChar)\n " + + " value - value to mask. Supported types: SMALLINT, INT, BIGINT, STRING, VARCHAR\n " + + " charCount - number of characters. Default value: 4\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: '1'\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. Specify -1 to retain original character. Default value: '1'\n " + ) +public class GenericUDFMaskShowLastN extends BaseMaskUDF { + public GenericUDFMaskShowLastN() { + super(new MaskShowLastNTransformer()); + } +} + +class MaskShowLastNTransformer extends MaskTransformer { + int charCount = 4; + + public MaskShowLastNTransformer() { + super(); + } + + @Override + public void init(ObjectInspector[] arguments, int argsStartIdx) { + super.init(arguments, argsStartIdx + 1); // first argument is charCount, which is consumed in this method below + + charCount = getIntArg(arguments, argsStartIdx, 4); + } + + @Override + String transform(String value) { + return maskString(value, 0, value.length() - charCount); + } + + @Override + Byte transform(Byte value) { + String strValue = value.toString(); + + return toByte(Long.parseLong(maskNumber(strValue, 0, strValue.length() - charCount))); + } + + @Override + Short transform(Short value) { + String strValue = value.toString(); + + return toShort(Long.parseLong(maskNumber(strValue, 0, strValue.length() - charCount))); + } + + @Override + Integer transform(Integer value) { + String strValue = value.toString(); + + return toInteger(Long.parseLong(maskNumber(strValue, 0, strValue.length() - charCount))); + } + + @Override + Long transform(Long value) { + String strValue = value.toString(); + + return Long.parseLong(maskNumber(strValue, 0, strValue.length() - charCount)); + } +} diff --git a/ql/src/test/queries/clientpositive/udf_mask.q b/ql/src/test/queries/clientpositive/udf_mask.q new file mode 100644 index 0000000..82b8ee7 --- /dev/null +++ b/ql/src/test/queries/clientpositive/udf_mask.q @@ -0,0 +1,13 @@ +DESCRIBE FUNCTION mask; +DESC FUNCTION EXTENDED mask; + +explain select mask('TestString-123', 'X', 'x', '0', '1'); + +select mask('TestString-123', 'X', 'x', '0', ':'), + mask(cast('TestString-123' as varchar(24)), 'X', 'x', '0', ':'), + mask(cast('TestString-123' as char(24)), 'X', 'x', '0', ':'), + mask(cast(123 as tinyint), -1, -1, -1, -1, '5'), + mask(cast(12345 as smallint), -1, -1, -1, -1, '5'), + mask(cast(12345 as int), -1, -1, -1, -1, '5'), + mask(cast(12345 as bigint), -1, -1, -1, -1, '5'), + mask(cast('2016-04-20' as date), -1, -1, -1, -1, -1, 0, 0, 0); diff --git a/ql/src/test/queries/clientpositive/udf_mask_first_n.q b/ql/src/test/queries/clientpositive/udf_mask_first_n.q new file mode 100644 index 0000000..3cd3962 --- /dev/null +++ b/ql/src/test/queries/clientpositive/udf_mask_first_n.q @@ -0,0 +1,13 @@ +DESCRIBE FUNCTION mask_first_n; +DESC FUNCTION EXTENDED mask_first_n; + +explain select mask_first_n('TestString-123', 4, 'X', 'x', '0', '1'); + +select mask_first_n('TestString-123', 4, 'X', 'x', '0', ':'), + mask_first_n(cast('TestString-123' as varchar(24)), 4, 'X', 'x', '0', ':'), + mask_first_n(cast('TestString-123' as char(24)), 4, 'X', 'x', '0', ':'), + mask_first_n(cast(123 as tinyint), 4, -1, -1, -1, -1, '5'), + mask_first_n(cast(12345 as smallint), 4, -1, -1, -1, -1, '5'), + mask_first_n(cast(12345 as int), 4, -1, -1, -1, -1, '5'), + mask_first_n(cast(12345 as bigint), 4, -1, -1, -1, -1, '5'), + mask_first_n(cast('2016-04-20' as date), 4, -1, -1, -1, -1, -1, 0, 0, 0); diff --git a/ql/src/test/queries/clientpositive/udf_mask_hash.q b/ql/src/test/queries/clientpositive/udf_mask_hash.q new file mode 100644 index 0000000..698f6b3 --- /dev/null +++ b/ql/src/test/queries/clientpositive/udf_mask_hash.q @@ -0,0 +1,13 @@ +DESCRIBE FUNCTION mask_hash; +DESC FUNCTION EXTENDED mask_hash; + +explain select mask_hash('TestString-123'); + +select mask_hash('TestString-123'), + mask_hash(cast('TestString-123' as varchar(24))), + mask_hash(cast('TestString-123' as char(24))), + mask_hash(cast(123 as tinyint)), + mask_hash(cast(12345 as smallint)), + mask_hash(cast(12345 as int)), + mask_hash(cast(12345 as bigint)), + mask_hash(cast('2016-04-20' as date)); diff --git a/ql/src/test/queries/clientpositive/udf_mask_last_n.q b/ql/src/test/queries/clientpositive/udf_mask_last_n.q new file mode 100644 index 0000000..89eb05d --- /dev/null +++ b/ql/src/test/queries/clientpositive/udf_mask_last_n.q @@ -0,0 +1,13 @@ +DESCRIBE FUNCTION mask_last_n; +DESC FUNCTION EXTENDED mask_last_n; + +explain select mask_last_n('TestString-123', 4, 'X', 'x', '0', '1'); + +select mask_last_n('TestString-123', 4, 'X', 'x', '0', ':'), + mask_last_n(cast('TestString-123' as varchar(24)), 4, 'X', 'x', '0', ':'), + mask_last_n(cast('TestString-123' as char(24)), 4, 'X', 'x', '0', ':'), + mask_last_n(cast(123 as tinyint), 4, -1, -1, -1, -1, '5'), + mask_last_n(cast(12345 as smallint), 4, -1, -1, -1, -1, '5'), + mask_last_n(cast(12345 as int), 4, -1, -1, -1, -1, '5'), + mask_last_n(cast(12345 as bigint), 4, -1, -1, -1, -1, '5'), + mask_last_n(cast('2016-04-20' as date), 4, -1, -1, -1, -1, -1, 0, 0, 0); diff --git a/ql/src/test/queries/clientpositive/udf_mask_show_first_n.q b/ql/src/test/queries/clientpositive/udf_mask_show_first_n.q new file mode 100644 index 0000000..1425a82 --- /dev/null +++ b/ql/src/test/queries/clientpositive/udf_mask_show_first_n.q @@ -0,0 +1,13 @@ +DESCRIBE FUNCTION mask_show_first_n; +DESC FUNCTION EXTENDED mask_show_first_n; + +explain select mask_show_first_n('TestString-123', 4, 'X', 'x', '0', '1'); + +select mask_show_first_n('TestString-123', 4, 'X', 'x', '0', ':'), + mask_show_first_n(cast('TestString-123' as varchar(24)), 4, 'X', 'x', '0', ':'), + mask_show_first_n(cast('TestString-123' as char(24)), 4, 'X', 'x', '0', ':'), + mask_show_first_n(cast(123 as tinyint), 4, -1, -1, -1, -1, '5'), + mask_show_first_n(cast(12345 as smallint), 4, -1, -1, -1, -1, '5'), + mask_show_first_n(cast(12345 as int), 4, -1, -1, -1, -1, '5'), + mask_show_first_n(cast(12345 as bigint), 4, -1, -1, -1, -1, '5'), + mask_show_first_n(cast('2016-04-20' as date), 4, -1, -1, -1, -1, -1, 0, 0, 0); diff --git a/ql/src/test/queries/clientpositive/udf_mask_show_last_n.q b/ql/src/test/queries/clientpositive/udf_mask_show_last_n.q new file mode 100644 index 0000000..c4d15fb --- /dev/null +++ b/ql/src/test/queries/clientpositive/udf_mask_show_last_n.q @@ -0,0 +1,13 @@ +DESCRIBE FUNCTION mask_show_last_n; +DESC FUNCTION EXTENDED mask_show_last_n; + +explain select mask_show_last_n('TestString-123', 4, 'X', 'x', '0', '1'); + +select mask_show_last_n('TestString-123', 4, 'X', 'x', '0', ':'), + mask_show_last_n(cast('TestString-123' as varchar(24)), 4, 'X', 'x', '0', ':'), + mask_show_last_n(cast('TestString-123' as char(24)), 4, 'X', 'x', '0', ':'), + mask_show_last_n(cast(123 as tinyint), 4, -1, -1, -1, -1, '5'), + mask_show_last_n(cast(12345 as smallint), 4, -1, -1, -1, -1, '5'), + mask_show_last_n(cast(12345 as int), 4, -1, -1, -1, -1, '5'), + mask_show_last_n(cast(12345 as bigint), 4, -1, -1, -1, -1, '5'), + mask_show_last_n(cast('2016-04-20' as date), 4, -1, -1, -1, -1, -1, 0, 0, 0); -- 2.6.4 (Apple Git-63)