Skip to content

Commit

Permalink
GIS #462: made 2nd argument optional for ST_GeoFromText; extended tes…
Browse files Browse the repository at this point in the history
…ts and validate for points before execution methods
  • Loading branch information
danylokravchenko committed Nov 12, 2023
1 parent e57239c commit 84f18b6
Show file tree
Hide file tree
Showing 8 changed files with 212 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ public enum Kind {
*/
DISTANCE,

/**
* GEO functions.
*/
GEO,

/**
* POSITION Function
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,8 @@ public Expression implement( RexToLixTranslator translator, RexCall call, List<E
// geo functions
defineMethod( OperatorRegistry.get( OperatorName.ST_GEOFROMTEXT ), BuiltInMethod.ST_GEO_FROM_TEXT.method, NullPolicy.STRICT );
defineMethod( OperatorRegistry.get( OperatorName.ST_X ), BuiltInMethod.ST_X.method, NullPolicy.STRICT );
defineMethod( OperatorRegistry.get( OperatorName.ST_Y ), BuiltInMethod.ST_Y.method, NullPolicy.STRICT );
defineMethod( OperatorRegistry.get( OperatorName.ST_Z ), BuiltInMethod.ST_Z.method, NullPolicy.STRICT );
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1308,9 +1308,26 @@ public enum OperatorName {
// GEO OPERATORS
//-------------------------------------------------------------

/**
* The <code>ST_GeoFromText</code> operator function: create the {@link org.polypheny.db.type.entity.spatial.PolyGeometry} from text
*/
ST_GEOFROMTEXT( Function.class ),

/**
* The <code>ST_X</code> operator function: receive the <strong>X</strong> coordinate of the {@link org.polypheny.db.type.entity.spatial.PolyPoint}
*/
ST_X( Function.class ),

/**
* The <code>ST_Y</code> operator function: receive the <strong>Y</strong> coordinate of the {@link org.polypheny.db.type.entity.spatial.PolyPoint}
*/
ST_Y( Function.class ),

/**
* The <code>ST_Z</code> operator function: receive the <strong>Z</strong> coordinate of the {@link org.polypheny.db.type.entity.spatial.PolyPoint}
*/
ST_Z( Function.class ),

//-------------------------------------------------------------
// SET OPERATORS
//-------------------------------------------------------------
Expand Down
44 changes: 38 additions & 6 deletions core/src/main/java/org/polypheny/db/functions/GeoFunctions.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,35 +20,67 @@

import org.polypheny.db.type.entity.PolyFloat;
import org.polypheny.db.type.entity.PolyString;
import org.polypheny.db.type.entity.category.PolyNumber;
import org.polypheny.db.type.entity.spatial.InvalidGeometryException;
import org.polypheny.db.type.entity.spatial.PolyGeometry;

/**
* Implementations of Geo functions
*/
public class GeoFunctions {

private static final String POINT_RESTRICTION = "This function could be applied only to points";


private GeoFunctions() {
// empty on purpose
}


@SuppressWarnings("UnusedDeclaration")
public static PolyGeometry stGeoFromText( PolyString wkt ) {
try {
return PolyGeometry.of( wkt.value );
} catch ( InvalidGeometryException e ) {
throw toUnchecked( e );
}
catch ( InvalidGeometryException e ) {
}


@SuppressWarnings("UnusedDeclaration")
public static PolyGeometry stGeoFromText( PolyString wkt, PolyNumber srid ) {
try {
return PolyGeometry.of( wkt.value, srid.intValue() );
} catch ( InvalidGeometryException e ) {
throw toUnchecked( e );
}
}


@SuppressWarnings("UnusedDeclaration")
public static PolyFloat stX( PolyGeometry geometry ) {
if (!geometry.isPoint()) {
throw toUnchecked( new InvalidGeometryException( "This function could be applied only to points" ));
}
restrictToPoints( geometry );
return PolyFloat.of( geometry.asPoint().getX() );
}

public static PolyString test1( PolyString wkt ) {
return wkt;

@SuppressWarnings("UnusedDeclaration")
public static PolyFloat stY( PolyGeometry geometry ) {
restrictToPoints( geometry );
return PolyFloat.of( geometry.asPoint().getY() );
}


@SuppressWarnings("UnusedDeclaration")
public static PolyFloat stZ( PolyGeometry geometry ) {
restrictToPoints( geometry );
return PolyFloat.of( geometry.asPoint().getZ() );
}

private static void restrictToPoints( PolyGeometry geometry ) {
if ( !geometry.isPoint() ) {
throw toUnchecked( new InvalidGeometryException( POINT_RESTRICTION ) );
}
}

}
2 changes: 2 additions & 0 deletions core/src/main/java/org/polypheny/db/util/BuiltInMethod.java
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,8 @@ public enum BuiltInMethod {
// GEO METHODS
ST_GEO_FROM_TEXT( GeoFunctions.class, "stGeoFromText", PolyString.class ),
ST_X( GeoFunctions.class, "stX", PolyGeometry.class ),
ST_Y( GeoFunctions.class, "stY", PolyGeometry.class ),
ST_Z( GeoFunctions.class, "stZ", PolyGeometry.class ),
/// MQL BUILT-IN METHODS
MQL_EQ( MqlFunctions.class, "docEq", PolyValue.class, PolyValue.class ),
MQL_GT( MqlFunctions.class, "docGt", PolyValue.class, PolyValue.class ),
Expand Down
34 changes: 28 additions & 6 deletions dbms/src/test/java/org/polypheny/db/sql/fun/GeoFunctionsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package org.polypheny.db.sql.fun;

import com.google.common.collect.ImmutableList;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
Expand Down Expand Up @@ -46,12 +47,33 @@ public void geoFromText() throws SQLException {
try ( TestHelper.JdbcConnection polyphenyDbConnection = new TestHelper.JdbcConnection( true ) ) {
Connection connection = polyphenyDbConnection.getConnection();
try ( Statement statement = connection.createStatement() ) {
ResultSet resultSet = statement.executeQuery( "SELECT ST_GeoFromText('Point(0 1)')" );
List<Object[]> received = TestHelper.convertResultSetToList( resultSet );
System.out.println(received);
resultSet = statement.executeQuery( "SELECT ST_X(ST_GeoFromText('Point(0 1)'))" );
received = TestHelper.convertResultSetToList( resultSet );
System.out.println(received);
// ST_GeoFromText with only 1 parameter (WKT)
TestHelper.checkResultSet(
statement.executeQuery( "SELECT ST_GeoFromText('POINT (0 1)')" ),
ImmutableList.of(
new Object[]{ "SRID=0;POINT (0 1)" }
) );
// ST_GeoFromText with 2 parameters (WKT, SRID)
TestHelper.checkResultSet(
statement.executeQuery( "SELECT ST_GeoFromText('POINT (0 1)', 1)" ),
ImmutableList.of(
new Object[]{ "SRID=1;POINT (0 1)" }
) );
}
}
}

@Test
public void pointFunctions() throws SQLException {
try ( TestHelper.JdbcConnection polyphenyDbConnection = new TestHelper.JdbcConnection( true ) ) {
Connection connection = polyphenyDbConnection.getConnection();
try ( Statement statement = connection.createStatement() ) {
// get X coordinate of the point
TestHelper.checkResultSet(
statement.executeQuery( "SELECT ST_X(ST_GeoFromText('POINT (0 1)'))" ),
ImmutableList.of(
new Object[]{ 0.0 }
) );
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2488,23 +2488,33 @@ public void unparse( SqlWriter writer, SqlCall call, int leftPrec, int rightPrec
register( OperatorName.UNWRAP_INTERVAL, new LangFunctionOperator( OperatorName.UNWRAP_INTERVAL.name(), Kind.OTHER_FUNCTION ) );

// GEO functions
// TODO: move it to separate class and add a varying argument [SRID] how it's done for distances
// register(
// OperatorName.ST_GEOFROMTEXT,
// new SqlFunction(
// "ST_GEOFROMTEXT",
// Kind.OTHER_FUNCTION,
// ReturnTypes.GEOMETRY,
// null,
// OperandTypes.STRING,
// FunctionCategory.GEOMETRY ) );
register( OperatorName.ST_GEOFROMTEXT, new SqlStGeoFromText() );

register(
OperatorName.ST_X,
new SqlFunction(
"ST_X",
Kind.OTHER_FUNCTION,
Kind.GEO,
ReturnTypes.DOUBLE,
InferTypes.GEOMETRY,
OperandTypes.GEOMETRY,
FunctionCategory.GEOMETRY ) );

register(
OperatorName.ST_Y,
new SqlFunction(
"ST_Y",
Kind.GEO,
ReturnTypes.DOUBLE,
InferTypes.GEOMETRY,
OperandTypes.GEOMETRY,
FunctionCategory.GEOMETRY ) );

register(
OperatorName.ST_Z,
new SqlFunction(
"ST_Z",
Kind.GEO,
ReturnTypes.DOUBLE,
InferTypes.GEOMETRY,
OperandTypes.GEOMETRY,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,123 @@

package org.polypheny.db.sql.language.fun;

import static org.polypheny.db.util.Static.RESOURCE;

import java.util.List;
import org.polypheny.db.algebra.constant.FunctionCategory;
import org.polypheny.db.algebra.constant.Kind;
import org.polypheny.db.algebra.type.AlgDataType;
import org.polypheny.db.nodes.CallBinding;
import org.polypheny.db.nodes.Operator;
import org.polypheny.db.sql.language.SqlFunction;
import org.polypheny.db.type.OperandCountRange;
import org.polypheny.db.type.PolyOperandCountRanges;
import org.polypheny.db.type.PolyTypeUtil;
import org.polypheny.db.type.checker.OperandTypes;
import org.polypheny.db.type.checker.PolyOperandTypeChecker;
import org.polypheny.db.type.inference.InferTypes;
import org.polypheny.db.type.inference.ReturnTypes;
import org.polypheny.db.util.CoreUtil;
import org.polypheny.db.util.Util;

/**
* Definition of the "ST_GeoFromText" spatial function.
* The function has a required parameter - WKT string representation
* and an optional SRID integer.
*/
public class SqlStGeoFromText extends SqlFunction {

private static final PolyOperandTypeChecker ST_GEOFROMTEXT_ARG_CHECKER = new PolyOperandTypeChecker() {

@Override
public boolean checkOperandTypes( CallBinding callBinding, boolean throwOnFailure ) {
int nOperandsActual = callBinding.getOperandCount();

// Make sure the first argument is not null
if ( CoreUtil.isNullLiteral( callBinding.operand( 0 ), false ) ) {
if ( throwOnFailure ) {
throw callBinding.getValidator().newValidationError( callBinding.operand( 0 ), RESOURCE.nullIllegal() );
} else {
return false;
}
}

// Make sure the first argument is a string
if ( !PolyTypeUtil.inCharFamily( callBinding.getOperandType( 0 ) ) ) {
if ( throwOnFailure ) {
throw callBinding.getValidator().newValidationError( callBinding.operand( 0 ), RESOURCE.expectedCharacter() );
} else {
return false;
}
}

// Check, if present, whether second argument is a number
if ( nOperandsActual == 2 ) {
if ( CoreUtil.isNullLiteral( callBinding.operand( 1 ), false ) ) {
if ( throwOnFailure ) {
throw callBinding.getValidator().newValidationError( callBinding.operand( 1 ), RESOURCE.nullIllegal() );
} else {
return false;
}
}

if ( (!PolyTypeUtil.isNumeric( callBinding.getOperandType( 1 ) )) ) {
if ( throwOnFailure ) {
throw callBinding.newValidationSignatureError();
} else {
return false;
}
}
}

return true;

}


@Override
public String getAllowedSignatures( Operator op, String opName ) {
return "'ST_GeoFromText(<STRING>)'" + "\n" + "'ST_GeoFromText(<STRING>, <INTEGER>)'";
}


@Override
public Consistency getConsistency() {
return Consistency.NONE;
}


@Override
public OperandCountRange getOperandCountRange() {
return PolyOperandCountRanges.between( 1, 2 );
}


@Override
public boolean isOptional( int i ) {
return i == 1;
}
};


/**
* Creates the SqlStGeoFromText.
*/
public SqlStGeoFromText() {
super(
"ST_GEOFROMTEXT",
Kind.OTHER_FUNCTION,
ReturnTypes.GEOMETRY,
null,
OperandTypes.STRING,
FunctionCategory.GEOMETRY );
super( "ST_GEOFROMTEXT", Kind.GEO, ReturnTypes.GEOMETRY, null, ST_GEOFROMTEXT_ARG_CHECKER, FunctionCategory.GEOMETRY );
}

// TODO: add varying arguments for SRID

@Override
public String getSignatureTemplate( int operandsCount ) {
switch ( operandsCount ) {
case 1:
return "{0}({1})";
case 2:
return "{0}({1}, {2})";
default:
throw new AssertionError();
}
}

}

0 comments on commit 84f18b6

Please sign in to comment.