use of io.trino.spi.function.SqlNullable in project trino by trinodb.
the class GeoFunctions method stSphericalArea.
@SqlNullable
@Description("Returns the area of a geometry on the Earth's surface using spherical model")
@ScalarFunction("ST_Area")
@SqlType(DOUBLE)
public static Double stSphericalArea(@SqlType(SPHERICAL_GEOGRAPHY_TYPE_NAME) Slice input) {
OGCGeometry geometry = deserialize(input);
if (geometry.isEmpty()) {
return null;
}
validateSphericalType("ST_Area", geometry, EnumSet.of(POLYGON, MULTI_POLYGON));
Polygon polygon = (Polygon) geometry.getEsriGeometry();
// See https://www.movable-type.co.uk/scripts/latlong.html
// and http://osgeo-org.1560.x6.nabble.com/Area-of-a-spherical-polygon-td3841625.html
// and https://www.element84.com/blog/determining-if-a-spherical-polygon-contains-a-pole
// for the underlying Maths
double sphericalExcess = 0.0;
int numPaths = polygon.getPathCount();
for (int i = 0; i < numPaths; i++) {
double sign = polygon.isExteriorRing(i) ? 1.0 : -1.0;
sphericalExcess += sign * Math.abs(computeSphericalExcess(polygon, polygon.getPathStart(i), polygon.getPathEnd(i)));
}
// isExteriorRing returns false for the exterior ring
return Math.abs(sphericalExcess * EARTH_RADIUS_M * EARTH_RADIUS_M);
}
use of io.trino.spi.function.SqlNullable in project trino by trinodb.
the class GeoFunctions method stY.
@SqlNullable
@Description("Return the Y coordinate of the point")
@ScalarFunction("ST_Y")
@SqlType(DOUBLE)
public static Double stY(@SqlType(GEOMETRY_TYPE_NAME) Slice input) {
OGCGeometry geometry = deserialize(input);
validateType("ST_Y", geometry, EnumSet.of(POINT));
if (geometry.isEmpty()) {
return null;
}
return ((OGCPoint) geometry).Y();
}
use of io.trino.spi.function.SqlNullable in project trino by trinodb.
the class GeoFunctions method stContains.
@SqlNullable
@Description("Returns TRUE if and only if no points of right lie in the exterior of left, and at least one point of the interior of left lies in the interior of right")
@ScalarFunction("ST_Contains")
@SqlType(BOOLEAN)
public static Boolean stContains(@SqlType(GEOMETRY_TYPE_NAME) Slice left, @SqlType(GEOMETRY_TYPE_NAME) Slice right) {
if (!envelopes(left, right, Envelope::contains)) {
return false;
}
OGCGeometry leftGeometry = deserialize(left);
OGCGeometry rightGeometry = deserialize(right);
verifySameSpatialReference(leftGeometry, rightGeometry);
return leftGeometry.contains(rightGeometry);
}
use of io.trino.spi.function.SqlNullable in project trino by trinodb.
the class StringFunctions method splitPart.
@SqlNullable
@Description("Splits a string by a delimiter and returns the specified field (counting from one)")
@ScalarFunction
@LiteralParameters({ "x", "y" })
@SqlType("varchar(x)")
public static Slice splitPart(@SqlType("varchar(x)") Slice string, @SqlType("varchar(y)") Slice delimiter, @SqlType(StandardTypes.BIGINT) long index) {
checkCondition(index > 0, INVALID_FUNCTION_ARGUMENT, "Index must be greater than zero");
// Empty delimiter? Then every character will be a split
if (delimiter.length() == 0) {
int startCodePoint = toIntExact(index);
int indexStart = offsetOfCodePoint(string, startCodePoint - 1);
if (indexStart < 0) {
// index too big
return null;
}
int length = lengthOfCodePoint(string, indexStart);
if (indexStart + length > string.length()) {
throw new TrinoException(INVALID_FUNCTION_ARGUMENT, "Invalid UTF-8 encoding");
}
return string.slice(indexStart, length);
}
int matchCount = 0;
int previousIndex = 0;
while (previousIndex < string.length()) {
int matchIndex = string.indexOf(delimiter, previousIndex);
// No match
if (matchIndex < 0) {
break;
}
// Reached the requested part?
if (++matchCount == index) {
return string.slice(previousIndex, matchIndex - previousIndex);
}
// Continue searching after the delimiter
previousIndex = matchIndex + delimiter.length();
}
if (matchCount == index - 1) {
// returns last section of the split
return string.slice(previousIndex, string.length() - previousIndex);
}
// index is too big, null is returned
return null;
}
use of io.trino.spi.function.SqlNullable in project trino by trinodb.
the class Re2JRegexpReplaceLambdaFunction method regexpReplace.
@LiteralParameters("x")
@SqlType("varchar")
@SqlNullable
public Slice regexpReplace(@SqlType("varchar") Slice source, @SqlType(Re2JRegexpType.NAME) Re2JRegexp pattern, @SqlType("function(array(varchar), varchar(x))") UnaryFunctionInterface replaceFunction) {
// If there is no match we can simply return the original source without doing copy.
Matcher matcher = pattern.matcher(source);
if (!matcher.find()) {
return source;
}
SliceOutput output = new DynamicSliceOutput(source.length());
// that will be passed to the lambda function.
if (pageBuilder.isFull()) {
pageBuilder.reset();
}
BlockBuilder blockBuilder = pageBuilder.getBlockBuilder(0);
int groupCount = matcher.groupCount();
int appendPosition = 0;
do {
int start = matcher.start();
int end = matcher.end();
// Append the un-matched part
if (appendPosition < start) {
output.writeBytes(source, appendPosition, start - appendPosition);
}
appendPosition = end;
// Append the capturing groups to the target block that will be passed to lambda
for (int i = 1; i <= groupCount; i++) {
Slice matchedGroupSlice = matcher.group(i);
if (matchedGroupSlice != null) {
VARCHAR.writeSlice(blockBuilder, matchedGroupSlice);
} else {
blockBuilder.appendNull();
}
}
pageBuilder.declarePositions(groupCount);
Block target = blockBuilder.getRegion(blockBuilder.getPositionCount() - groupCount, groupCount);
// Call the lambda function to replace the block, and append the result to output
Slice replaced = (Slice) replaceFunction.apply(target);
if (replaced == null) {
// replacing a substring with null (unknown) makes the entire string null
return null;
}
output.appendBytes(replaced);
} while (matcher.find());
// Append the rest of un-matched
output.writeBytes(source, appendPosition, source.length() - appendPosition);
return output.slice();
}
Aggregations