/* * Licensed 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 com.facebook.presto.operator.scalar; import com.facebook.presto.spi.function.LiteralParameters; import com.facebook.presto.spi.function.OperatorType; import com.facebook.presto.spi.function.ScalarOperator; import com.facebook.presto.spi.function.SqlType; import com.facebook.presto.type.LiteralParameter; import io.airlift.slice.Slice; import static com.facebook.presto.spi.type.Chars.padSpaces; import static com.facebook.presto.spi.type.Chars.trimSpaces; import static com.facebook.presto.spi.type.Chars.trimSpacesAndTruncateToLength; import static com.facebook.presto.spi.type.Varchars.truncateToLength; import static io.airlift.slice.SliceUtf8.countCodePoints; import static io.airlift.slice.SliceUtf8.offsetOfCodePoint; import static io.airlift.slice.Slices.EMPTY_SLICE; public final class CharacterStringCasts { private CharacterStringCasts() {} @ScalarOperator(OperatorType.CAST) @SqlType("varchar(y)") @LiteralParameters({"x", "y"}) public static Slice varcharToVarcharCast(@LiteralParameter("x") Long x, @LiteralParameter("y") Long y, @SqlType("varchar(x)") Slice slice) { if (x > y) { return truncateToLength(slice, y.intValue()); } else { return slice; } } @ScalarOperator(OperatorType.CAST) @SqlType("char(y)") @LiteralParameters({"x", "y"}) public static Slice charToCharCast(@LiteralParameter("x") Long x, @LiteralParameter("y") Long y, @SqlType("char(x)") Slice slice) { if (x > y) { return truncateToLength(slice, y.intValue()); } else { return slice; } } @ScalarOperator(OperatorType.CAST) @SqlType("char(y)") @LiteralParameters({"x", "y"}) public static Slice varcharToCharCast(@LiteralParameter("y") Long y, @SqlType("varchar(x)") Slice slice) { return trimSpacesAndTruncateToLength(slice, y.intValue()); } @ScalarOperator(OperatorType.CAST) @SqlType("varchar(y)") @LiteralParameters({"x", "y"}) public static Slice charToVarcharCast(@LiteralParameter("x") Long x, @LiteralParameter("y") Long y, @SqlType("char(x)") Slice slice) { if (x.intValue() <= y.intValue()) { return padSpaces(slice, x.intValue()); } return padSpaces(truncateToLength(slice, y.intValue()), y.intValue()); } @ScalarOperator(OperatorType.SATURATED_FLOOR_CAST) @SqlType("char(y)") @LiteralParameters({"x", "y"}) // This function returns Char(y) value that is smaller than original Varchar(x) value. However, it is not necessarily the largest // Char(y) value that is smaller than the original Varchar(x) value. This is fine though for usage in TupleDomainTranslator. public static Slice varcharToCharSaturatedFloorCast(@LiteralParameter("y") Long y, @SqlType("varchar(x)") Slice slice) { Slice trimmedSlice = trimSpaces(slice); int trimmedTextLength = countCodePoints(trimmedSlice); int numberOfTrailingSpaces = slice.length() - trimmedSlice.length(); // if Varchar(x) value length (including spaces) is greater than y, we can just truncate it if (trimmedTextLength + numberOfTrailingSpaces >= y) { return truncateToLength(trimmedSlice, y.intValue()); } if (trimmedTextLength == 0) { return EMPTY_SLICE; } // if Varchar(x) value length (including spaces) is smaller than y, we truncate all spaces // and also remove one additional trailing character to get smaller Char(y) value return trimmedSlice.slice(0, offsetOfCodePoint(trimmedSlice, trimmedTextLength - 1)); } }