use of io.trino.spi.function.Description in project trino by trinodb.
the class StringFunctions method substring.
@Description("Substring of given length starting at an index")
@ScalarFunction(alias = "substr")
@LiteralParameters("x")
@SqlType("varchar(x)")
public static Slice substring(@SqlType("varchar(x)") Slice utf8, @SqlType(StandardTypes.BIGINT) long start, @SqlType(StandardTypes.BIGINT) long length) {
if (start == 0 || (length <= 0) || (utf8.length() == 0)) {
return Slices.EMPTY_SLICE;
}
int startCodePoint = Ints.saturatedCast(start);
int lengthCodePoints = Ints.saturatedCast(length);
if (startCodePoint > 0) {
int indexStart = offsetOfCodePoint(utf8, startCodePoint - 1);
if (indexStart < 0) {
// before beginning of string
return Slices.EMPTY_SLICE;
}
int indexEnd = offsetOfCodePoint(utf8, indexStart, lengthCodePoints);
if (indexEnd < 0) {
// after end of string
indexEnd = utf8.length();
}
return utf8.slice(indexStart, indexEnd - indexStart);
}
// negative start is relative to end of string
int codePoints = countCodePoints(utf8);
startCodePoint += codePoints;
// before beginning of string
if (startCodePoint < 0) {
return Slices.EMPTY_SLICE;
}
int indexStart = offsetOfCodePoint(utf8, startCodePoint);
int indexEnd;
if (startCodePoint + lengthCodePoints < codePoints) {
indexEnd = offsetOfCodePoint(utf8, indexStart, lengthCodePoints);
} else {
indexEnd = utf8.length();
}
return utf8.slice(indexStart, indexEnd - indexStart);
}
use of io.trino.spi.function.Description in project trino by trinodb.
the class StringFunctions method levenshteinDistance.
@Description("Computes Levenshtein distance between two strings")
@ScalarFunction
@LiteralParameters({ "x", "y" })
@SqlType(StandardTypes.BIGINT)
public static long levenshteinDistance(@SqlType("varchar(x)") Slice left, @SqlType("varchar(y)") Slice right) {
int[] leftCodePoints = castToCodePoints(left);
int[] rightCodePoints = castToCodePoints(right);
if (leftCodePoints.length < rightCodePoints.length) {
int[] tempCodePoints = leftCodePoints;
leftCodePoints = rightCodePoints;
rightCodePoints = tempCodePoints;
}
if (rightCodePoints.length == 0) {
return leftCodePoints.length;
}
checkCondition((leftCodePoints.length * (rightCodePoints.length - 1)) <= 1_000_000, INVALID_FUNCTION_ARGUMENT, "The combined inputs for Levenshtein distance are too large");
int[] distances = new int[rightCodePoints.length];
for (int i = 0; i < rightCodePoints.length; i++) {
distances[i] = i + 1;
}
for (int i = 0; i < leftCodePoints.length; i++) {
int leftUpDistance = distances[0];
if (leftCodePoints[i] == rightCodePoints[0]) {
distances[0] = i;
} else {
distances[0] = Math.min(i, distances[0]) + 1;
}
for (int j = 1; j < rightCodePoints.length; j++) {
int leftUpDistanceNext = distances[j];
if (leftCodePoints[i] == rightCodePoints[j]) {
distances[j] = leftUpDistance;
} else {
distances[j] = Math.min(distances[j - 1], Math.min(leftUpDistance, distances[j])) + 1;
}
leftUpDistance = leftUpDistanceNext;
}
}
return distances[rightCodePoints.length - 1];
}
use of io.trino.spi.function.Description in project trino by trinodb.
the class StringFunctions method translate.
@Description("Translate characters from the source string based on original and translations strings")
@ScalarFunction
@LiteralParameters({ "x", "y", "z" })
@SqlType(StandardTypes.VARCHAR)
public static Slice translate(@SqlType("varchar(x)") Slice source, @SqlType("varchar(y)") Slice from, @SqlType("varchar(z)") Slice to) {
int[] fromCodePoints = castToCodePoints(from);
int[] toCodePoints = castToCodePoints(to);
Int2IntOpenHashMap map = new Int2IntOpenHashMap(fromCodePoints.length);
for (int index = 0; index < fromCodePoints.length; index++) {
int fromCodePoint = fromCodePoints[index];
map.putIfAbsent(fromCodePoint, index < toCodePoints.length ? toCodePoints[index] : -1);
}
int[] sourceCodePoints = castToCodePoints(source);
int[] targetCodePoints = new int[sourceCodePoints.length];
int targetPositions = 0;
int targetBytes = 0;
for (int index = 0; index < sourceCodePoints.length; index++) {
int codePoint = sourceCodePoints[index];
if (map.containsKey(codePoint)) {
int translatedCodePoint = map.get(codePoint);
if (translatedCodePoint == -1) {
continue;
}
codePoint = translatedCodePoint;
}
targetCodePoints[targetPositions++] = codePoint;
targetBytes += lengthOfCodePoint(codePoint);
}
Slice target = Slices.allocate(targetBytes);
int offset = 0;
for (int index = 0; index < targetPositions; index++) {
offset += setCodePointAt(targetCodePoints[index], target, offset);
}
return target;
}
use of io.trino.spi.function.Description in project trino by trinodb.
the class BingTileFunctions method geometryToBingTiles.
@Description("Given a geometry and a zoom level, returns the minimum set of Bing tiles that fully covers that geometry")
@ScalarFunction("geometry_to_bing_tiles")
@SqlType("array(" + BingTileType.NAME + ")")
public static Block geometryToBingTiles(@SqlType(GEOMETRY_TYPE_NAME) Slice input, @SqlType(StandardTypes.INTEGER) long zoomLevelInput) {
checkZoomLevel(zoomLevelInput);
int zoomLevel = toIntExact(zoomLevelInput);
OGCGeometry ogcGeometry = deserialize(input);
if (ogcGeometry.isEmpty()) {
return EMPTY_TILE_ARRAY;
}
Envelope envelope = getEnvelope(ogcGeometry);
checkLatitude(envelope.getYMin(), LATITUDE_SPAN_OUT_OF_RANGE);
checkLatitude(envelope.getYMax(), LATITUDE_SPAN_OUT_OF_RANGE);
checkLongitude(envelope.getXMin(), LONGITUDE_SPAN_OUT_OF_RANGE);
checkLongitude(envelope.getXMax(), LONGITUDE_SPAN_OUT_OF_RANGE);
boolean pointOrRectangle = isPointOrRectangle(ogcGeometry, envelope);
BingTile leftUpperTile = latitudeLongitudeToTile(envelope.getYMax(), envelope.getXMin(), zoomLevel);
BingTile rightLowerTile = getTileCoveringLowerRightCorner(envelope, zoomLevel);
// XY coordinates start at (0,0) in the left upper corner and increase left to right and top to bottom
long tileCount = (long) (rightLowerTile.getX() - leftUpperTile.getX() + 1) * (rightLowerTile.getY() - leftUpperTile.getY() + 1);
checkGeometryToBingTilesLimits(ogcGeometry, envelope, pointOrRectangle, tileCount, zoomLevel);
BlockBuilder blockBuilder = BIGINT.createBlockBuilder(null, toIntExact(tileCount));
if (pointOrRectangle || zoomLevel <= OPTIMIZED_TILING_MIN_ZOOM_LEVEL) {
// all tiles covering the bounding box intersect the geometry.
for (int x = leftUpperTile.getX(); x <= rightLowerTile.getX(); x++) {
for (int y = leftUpperTile.getY(); y <= rightLowerTile.getY(); y++) {
BingTile tile = BingTile.fromCoordinates(x, y, zoomLevel);
if (pointOrRectangle || !disjoint(tileToEnvelope(tile), ogcGeometry)) {
BIGINT.writeLong(blockBuilder, tile.encode());
}
}
}
} else {
// Intersection checks above are expensive. The logic below attempts to reduce the number
// of these checks. The idea is to identify large tiles which are fully covered by the
// geometry. For each such tile, we can cheaply compute all the containing tiles at
// the right zoom level and append them to results in bulk. This way we perform a single
// containment check instead of 2 to the power of level delta intersection checks, where
// level delta is the difference between the desired zoom level and level of the large
// tile covered by the geometry.
BingTile[] tiles = getTilesInBetween(leftUpperTile, rightLowerTile, OPTIMIZED_TILING_MIN_ZOOM_LEVEL);
for (BingTile tile : tiles) {
appendIntersectingSubtiles(ogcGeometry, zoomLevel, tile, blockBuilder);
}
}
return blockBuilder.build();
}
use of io.trino.spi.function.Description in project trino by trinodb.
the class GeoFunctions method toSphericalGeography.
@Description("Converts a Geometry object to a SphericalGeography object")
@ScalarFunction("to_spherical_geography")
@SqlType(SPHERICAL_GEOGRAPHY_TYPE_NAME)
public static Slice toSphericalGeography(@SqlType(GEOMETRY_TYPE_NAME) Slice input) {
// "every point in input is in range" <=> "the envelope of input is in range"
Envelope envelope = deserializeEnvelope(input);
if (!envelope.isEmpty()) {
checkLatitude(envelope.getYMin());
checkLatitude(envelope.getYMax());
checkLongitude(envelope.getXMin());
checkLongitude(envelope.getXMax());
}
OGCGeometry geometry = deserialize(input);
if (geometry.is3D()) {
throw new TrinoException(INVALID_FUNCTION_ARGUMENT, "Cannot convert 3D geometry to a spherical geography");
}
GeometryCursor cursor = geometry.getEsriGeometryCursor();
while (true) {
com.esri.core.geometry.Geometry subGeometry = cursor.next();
if (subGeometry == null) {
break;
}
if (!GEOMETRY_TYPES_FOR_SPHERICAL_GEOGRAPHY.contains(subGeometry.getType())) {
throw new TrinoException(INVALID_FUNCTION_ARGUMENT, "Cannot convert geometry of this type to spherical geography: " + subGeometry.getType());
}
}
return input;
}
Aggregations