
oracle.kv.impl.query.compiler.FuncGeoSearch Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of oracle-nosql-server Show documentation
Show all versions of oracle-nosql-server Show documentation
NoSQL Database Server - supplies build and runtime support for the server (store) side of the Oracle NoSQL Database.
The newest version!
/*-
* Copyright (C) 2011, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This file was distributed by Oracle as part of a version of Oracle NoSQL
* Database made available at:
*
* http://www.oracle.com/technetwork/database/database-technologies/nosqldb/downloads/index.html
*
* Please see the LICENSE file included in the top-level directory of the
* appropriate version of Oracle NoSQL Database for a copy of the license and
* additional information.
*/
package oracle.kv.impl.query.compiler;
import java.util.ArrayList;
import java.util.List;
import oracle.kv.impl.api.table.FieldDefImpl;
import oracle.kv.impl.api.table.FieldValueImpl;
import oracle.kv.impl.api.table.Geometry;
import oracle.kv.impl.query.QueryException;
import oracle.kv.impl.query.QueryException.Location;
import oracle.kv.impl.query.compiler.Expr.ConstKind;
import oracle.kv.impl.query.compiler.Expr.ExprKind;
import oracle.kv.impl.query.compiler.FunctionLib.FuncCode;
import oracle.kv.impl.query.runtime.FuncGeoSearchIter;
import oracle.kv.impl.query.runtime.PlanIter;
import oracle.kv.impl.query.types.ExprType;
import oracle.kv.impl.query.types.TypeManager;
/*
* boolean geo_interacts(any*, any*)
*
* boolean geo_is_inside(any*, any*)
*
* boolean geo_within_distance(any*, any*, double)
*
* boolean geo_near(any*, any*, double)
*
* Returns NULL if any operand returns NULL.
* Returns false if any operand returns zero or more than 1 items.
* Returns false if any of the operands is not a geometry
* For geo_is_inside, the 2nd operand should be a polygon; return false if not.
*/
public class FuncGeoSearch extends Function {
FuncGeoSearch(FuncCode code, String name, ArrayList geoTypes) {
super(code,
name,
geoTypes,
TypeManager.BOOLEAN_ONE(),
true);
}
@Override
boolean mayReturnNULL(ExprFuncCall fncall) {
return (fncall.getArg(0).mayReturnNULL() ||
fncall.getArg(1).mayReturnNULL() ||
(fncall.getNumArgs() > 2 &&
fncall.getArg(2).mayReturnNULL()));
}
@Override
Expr normalizeCall(ExprFuncCall fncall) {
normalizeArg(fncall, 0);
normalizeArg(fncall, 1);
if (theCode == FuncCode.FN_GEO_WITHIN_DISTANCE ||
theCode == FuncCode.FN_GEO_NEAR) {
Expr radiusExpr = fncall.getArg(2);
if (ConstKind.isCompileConst(radiusExpr) &&
radiusExpr.getKind() != ExprKind.CONST) {
QueryControlBlock qcb = fncall.getQCB();
StaticContext sctx = fncall.getSctx();
Location loc = radiusExpr.getLocation();
List res = ExprUtils.computeConstExpr(radiusExpr);
if (res.size() == 0) {
throw new QueryException(
"The distance operand of the geo_within_distance" +
"function is an empty sequence.", loc);
}
if (res.size() > 1) {
throw new QueryException(
"The distance operand of the geo_within_distance " +
"function is a sequence with more than one items.", loc);
}
radiusExpr = new ExprConst(qcb, sctx, loc, res.get(0));
fncall.setArg(2, radiusExpr, true);
}
}
return fncall;
}
static void normalizeArg(ExprFuncCall fncall, int i) {
Function func = fncall.getFunction();
FuncCode funcCode = func.getCode();
String funcName = func.getName();
String lr = (i == 0 ? "left" : "right");
Expr arg = fncall.getArg(i);
FieldDefImpl argDef = arg.getType().getDef();
if (!argDef.mayBeJsonObject()) {
throw new QueryException(
"The " + lr +" operand of the " + funcName +
" function is not a json object." +
" arg type = " + argDef.getDDLString(),
arg.getLocation());
}
if (ConstKind.isCompileConst(arg) && arg.getKind() != ExprKind.CONST) {
QueryControlBlock qcb = fncall.getQCB();
StaticContext sctx = fncall.getSctx();
List res = ExprUtils.computeConstExpr(arg);
if (res.size() == 0) {
throw new QueryException(
"The " + lr + " operand of the " + funcName +
" function is an empty sequence.",
arg.getLocation());
}
if (res.size() > 1) {
throw new QueryException(
"The " + lr + " operand of the " + funcName +
" function is a sequence with more than one items.",
arg.getLocation());
}
Geometry geom = CompilerAPI.getGeoUtils().
castAsGeometry(res.get(0));
if (geom == null) {
throw new QueryException(
"The " + lr + " operand of the " + funcName +
" function is not a valid geometry.",
arg.getLocation());
}
if (funcCode == FuncCode.FN_GEO_INSIDE &&
i == 1 &&
!geom.isPolygon()) {
throw new QueryException(
"The second argument to the geo_inside " +
"function is not a polygon.", fncall.getLocation());
}
arg = new ExprConst(qcb, sctx, arg.getLocation(), res.get(0));
fncall.setArg(i, arg, true);
}
}
@Override
PlanIter codegen(
CodeGenerator codegen,
ExprFuncCall fncall,
PlanIter[] argIters) {
int resultReg = codegen.allocateResultReg(fncall);
return new FuncGeoSearchIter(fncall, theCode, resultReg, argIters);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy