org.nlpcn.es4sql.parse.WhereParser Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of elasticsearch-sql Show documentation
Show all versions of elasticsearch-sql Show documentation
Query elasticsearch using SQL
package org.nlpcn.es4sql.parse;
import com.alibaba.druid.sql.ast.expr.*;
import com.alibaba.druid.sql.ast.statement.*;
import com.alibaba.druid.sql.ast.*;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.nlpcn.es4sql.SQLFunctions;
import org.nlpcn.es4sql.Util;
import org.nlpcn.es4sql.domain.*;
import org.nlpcn.es4sql.exception.SqlParseException;
import org.nlpcn.es4sql.spatial.SpatialParamsFactory;
import java.util.ArrayList;
import java.util.List;
/**
* Created by allwefantasy on 9/2/16.
*/
public class WhereParser {
private MySqlSelectQueryBlock query;
private SQLDeleteStatement delete;
private SQLExpr where;
private SqlParser sqlParser;
public WhereParser(SqlParser sqlParser, MySqlSelectQueryBlock query) {
this.sqlParser = sqlParser;
this.query = query;
this.where = query.getWhere();
}
public WhereParser(SqlParser sqlParser, SQLDeleteStatement delete) {
this.sqlParser = sqlParser;
this.delete = delete;
this.where = delete.getWhere();
}
public WhereParser(SqlParser sqlParser, SQLExpr expr) {
this.sqlParser = sqlParser;
this.where = expr;
}
public WhereParser(SqlParser sqlParser) {
this.sqlParser = sqlParser;
}
public Where findWhere() throws SqlParseException {
if (where == null) {
return null;
}
Where myWhere = Where.newInstance();
parseWhere(where, myWhere);
return myWhere;
}
public void parseWhere(SQLExpr expr, Where where) throws SqlParseException {
if (expr instanceof SQLBinaryOpExpr) {
SQLBinaryOpExpr bExpr = (SQLBinaryOpExpr) expr;
if (explanSpecialCondWithBothSidesAreLiterals(bExpr, where)) {
return;
}
if (explanSpecialCondWithBothSidesAreProperty(bExpr, where)) {
return;
}
}
if (expr instanceof SQLBinaryOpExpr && !isCond((SQLBinaryOpExpr) expr)) {
SQLBinaryOpExpr bExpr = (SQLBinaryOpExpr) expr;
routeCond(bExpr, bExpr.getLeft(), where);
routeCond(bExpr, bExpr.getRight(), where);
} else if (expr instanceof SQLNotExpr) {
parseWhere(((SQLNotExpr) expr).getExpr(), where);
negateWhere(where);
} else {
explanCond("AND", expr, where);
}
}
private void negateWhere(Where where) throws SqlParseException {
for (Where sub : where.getWheres()) {
if (sub instanceof Condition) {
Condition cond = (Condition) sub;
cond.setOpear(cond.getOpear().negative());
} else {
negateWhere(sub);
}
sub.setConn(sub.getConn().negative());
}
}
//some where conditions eg. 1=1 or 3>2 or 'a'='b'
private boolean explanSpecialCondWithBothSidesAreLiterals(SQLBinaryOpExpr bExpr, Where where) throws SqlParseException {
if ((bExpr.getLeft() instanceof SQLNumericLiteralExpr || bExpr.getLeft() instanceof SQLCharExpr) &&
(bExpr.getRight() instanceof SQLNumericLiteralExpr || bExpr.getRight() instanceof SQLCharExpr)
) {
SQLMethodInvokeExpr sqlMethodInvokeExpr = new SQLMethodInvokeExpr("script", null);
String operator = bExpr.getOperator().getName();
if (operator.equals("=")) {
operator = "==";
}
sqlMethodInvokeExpr.addParameter(
new SQLCharExpr(Util.expr2Object(bExpr.getLeft(), "'") +
" " + operator + " " +
Util.expr2Object(bExpr.getRight(), "'"))
);
explanCond("AND", sqlMethodInvokeExpr, where);
return true;
}
return false;
}
//some where conditions eg. field1=field2 or field1>field2
private boolean explanSpecialCondWithBothSidesAreProperty(SQLBinaryOpExpr bExpr, Where where) throws SqlParseException {
//join is not support
if ((bExpr.getLeft() instanceof SQLPropertyExpr || bExpr.getLeft() instanceof SQLIdentifierExpr) &&
(bExpr.getRight() instanceof SQLPropertyExpr || bExpr.getRight() instanceof SQLIdentifierExpr) &&
Sets.newHashSet("=", "<", ">", ">=", "<=").contains(bExpr.getOperator().getName()) &&
!Util.isFromJoinOrUnionTable(bExpr)
) {
SQLMethodInvokeExpr sqlMethodInvokeExpr = new SQLMethodInvokeExpr("script", null);
String operator = bExpr.getOperator().getName();
if (operator.equals("=")) {
operator = "==";
}
String leftProperty = Util.expr2Object(bExpr.getLeft()).toString();
String rightProperty = Util.expr2Object(bExpr.getRight()).toString();
if (leftProperty.split("\\.").length > 1) {
leftProperty = leftProperty.substring(leftProperty.split("\\.")[0].length() + 1);
}
if (rightProperty.split("\\.").length > 1) {
rightProperty = rightProperty.substring(rightProperty.split("\\.")[0].length() + 1);
}
sqlMethodInvokeExpr.addParameter(new SQLCharExpr(
"doc['" + leftProperty + "'].value " +
operator +
" doc['" + rightProperty + "'].value"));
explanCond("AND", sqlMethodInvokeExpr, where);
return true;
}
return false;
}
private boolean isCond(SQLBinaryOpExpr expr) {
SQLExpr leftSide = expr.getLeft();
if (leftSide instanceof SQLMethodInvokeExpr) {
return isAllowedMethodOnConditionLeft((SQLMethodInvokeExpr) leftSide, expr.getOperator());
}
return leftSide instanceof SQLIdentifierExpr ||
leftSide instanceof SQLPropertyExpr ||
leftSide instanceof SQLVariantRefExpr;
}
private boolean isAllowedMethodOnConditionLeft(SQLMethodInvokeExpr method, SQLBinaryOperator operator) {
return (method.getMethodName().toLowerCase().equals("nested") ||
method.getMethodName().toLowerCase().equals("children") ||
SQLFunctions.buildInFunctions.contains(method.getMethodName().toLowerCase())
) &&
!operator.isLogical();
}
private void routeCond(SQLBinaryOpExpr bExpr, SQLExpr sub, Where where) throws SqlParseException {
if (sub instanceof SQLBinaryOpExpr && !isCond((SQLBinaryOpExpr) sub)) {
SQLBinaryOpExpr binarySub = (SQLBinaryOpExpr) sub;
if (binarySub.getOperator().priority != bExpr.getOperator().priority) {
Where subWhere = new Where(bExpr.getOperator().name);
where.addWhere(subWhere);
parseWhere(binarySub, subWhere);
} else {
parseWhere(binarySub, where);
}
} else if (sub instanceof SQLNotExpr) {
Where subWhere = new Where(bExpr.getOperator().name);
where.addWhere(subWhere);
parseWhere(((SQLNotExpr) sub).getExpr(), subWhere);
negateWhere(subWhere);
} else {
explanCond(bExpr.getOperator().name, sub, where);
}
}
private void explanCond(String opear, SQLExpr expr, Where where) throws SqlParseException {
if (expr instanceof SQLBinaryOpExpr) {
SQLBinaryOpExpr soExpr = (SQLBinaryOpExpr) expr;
boolean methodAsOpear = false;
boolean isNested = false;
boolean isChildren = false;
NestedType nestedType = new NestedType();
if (nestedType.tryFillFromExpr(soExpr.getLeft())) {
soExpr.setLeft(new SQLIdentifierExpr(nestedType.field));
isNested = true;
}
ChildrenType childrenType = new ChildrenType();
if (childrenType.tryFillFromExpr(soExpr.getLeft())) {
soExpr.setLeft(new SQLIdentifierExpr(childrenType.field));
isChildren = true;
}
if (soExpr.getRight() instanceof SQLMethodInvokeExpr) {
SQLMethodInvokeExpr method = (SQLMethodInvokeExpr) soExpr.getRight();
String methodName = method.getMethodName().toLowerCase();
if (Condition.OPEAR.methodNameToOpear.containsKey(methodName)) {
Object[] methodParametersValue = getMethodValuesWithSubQueries(method);
Condition condition = null;
if (isNested)
condition = new Condition(Where.CONN.valueOf(opear), soExpr.getLeft().toString(), soExpr.getLeft(), Condition.OPEAR.methodNameToOpear.get(methodName), methodParametersValue, soExpr.getRight(), nestedType);
else if (isChildren)
condition = new Condition(Where.CONN.valueOf(opear), soExpr.getLeft().toString(), soExpr.getLeft(), Condition.OPEAR.methodNameToOpear.get(methodName), methodParametersValue, soExpr.getRight(), childrenType);
else
condition = new Condition(Where.CONN.valueOf(opear), soExpr.getLeft().toString(), soExpr.getLeft(), Condition.OPEAR.methodNameToOpear.get(methodName), methodParametersValue, soExpr.getRight(), null);
where.addWhere(condition);
methodAsOpear = true;
}
}
if (!methodAsOpear) {
Condition condition = null;
if (isNested)
condition = new Condition(Where.CONN.valueOf(opear), soExpr.getLeft().toString(), soExpr.getLeft(), soExpr.getOperator().name, parseValue(soExpr.getRight()), soExpr.getRight(), nestedType);
else if (isChildren)
condition = new Condition(Where.CONN.valueOf(opear), soExpr.getLeft().toString(), soExpr.getLeft(), soExpr.getOperator().name, parseValue(soExpr.getRight()), soExpr.getRight(), childrenType);
else {
SQLMethodInvokeExpr sqlMethodInvokeExpr = parseSQLBinaryOpExprWhoIsConditionInWhere(soExpr);
if (sqlMethodInvokeExpr == null) {
condition = new Condition(Where.CONN.valueOf(opear), soExpr.getLeft().toString(), soExpr.getLeft(), soExpr.getOperator().name, parseValue(soExpr.getRight()), soExpr.getRight(), null);
} else {
ScriptFilter scriptFilter = new ScriptFilter();
if (!scriptFilter.tryParseFromMethodExpr(sqlMethodInvokeExpr)) {
throw new SqlParseException("could not parse script filter");
}
condition = new Condition(Where.CONN.valueOf(opear), null, null, "SCRIPT", scriptFilter, null);
}
}
where.addWhere(condition);
}
} else if (expr instanceof SQLInListExpr) {
SQLInListExpr siExpr = (SQLInListExpr) expr;
String leftSide = siExpr.getExpr().toString();
boolean isNested = false;
boolean isChildren = false;
NestedType nestedType = new NestedType();
if (nestedType.tryFillFromExpr(siExpr.getExpr())) {
leftSide = nestedType.field;
isNested = false;
}
ChildrenType childrenType = new ChildrenType();
if (childrenType.tryFillFromExpr(siExpr.getExpr())) {
leftSide = childrenType.field;
isChildren = true;
}
Condition condition = null;
if (isNested)
condition = new Condition(Where.CONN.valueOf(opear), leftSide, null, siExpr.isNot() ? "NOT IN" : "IN", parseValue(siExpr.getTargetList()), null, nestedType);
else if (isChildren)
condition = new Condition(Where.CONN.valueOf(opear), leftSide, null, siExpr.isNot() ? "NOT IN" : "IN", parseValue(siExpr.getTargetList()), null, childrenType);
else
condition = new Condition(Where.CONN.valueOf(opear), leftSide, null, siExpr.isNot() ? "NOT IN" : "IN", parseValue(siExpr.getTargetList()), null);
where.addWhere(condition);
} else if (expr instanceof SQLBetweenExpr) {
SQLBetweenExpr between = ((SQLBetweenExpr) expr);
String leftSide = between.getTestExpr().toString();
boolean isNested = false;
boolean isChildren = false;
NestedType nestedType = new NestedType();
if (nestedType.tryFillFromExpr(between.getTestExpr())) {
leftSide = nestedType.field;
isNested = true;
}
ChildrenType childrenType = new ChildrenType();
if (childrenType.tryFillFromExpr(between.getTestExpr())) {
leftSide = childrenType.field;
isChildren = true;
}
Condition condition = null;
if (isNested)
condition = new Condition(Where.CONN.valueOf(opear), leftSide, null, between.isNot() ? "NOT BETWEEN" : "BETWEEN", new Object[]{parseValue(between.beginExpr), parseValue(between.endExpr)}, null, nestedType);
else if (isChildren)
condition = new Condition(Where.CONN.valueOf(opear), leftSide, null, between.isNot() ? "NOT BETWEEN" : "BETWEEN", new Object[]{parseValue(between.beginExpr), parseValue(between.endExpr)}, null, childrenType);
else
condition = new Condition(Where.CONN.valueOf(opear), leftSide, null, between.isNot() ? "NOT BETWEEN" : "BETWEEN", new Object[]{parseValue(between.beginExpr), parseValue(between.endExpr)}, null, null);
where.addWhere(condition);
} else if (expr instanceof SQLMethodInvokeExpr) {
SQLMethodInvokeExpr methodExpr = (SQLMethodInvokeExpr) expr;
List methodParameters = methodExpr.getParameters();
String methodName = methodExpr.getMethodName();
if (SpatialParamsFactory.isAllowedMethod(methodName)) {
String fieldName = methodParameters.get(0).toString();
boolean isNested = false;
boolean isChildren = false;
NestedType nestedType = new NestedType();
if (nestedType.tryFillFromExpr(methodParameters.get(0))) {
fieldName = nestedType.field;
isNested = true;
}
ChildrenType childrenType = new ChildrenType();
if (childrenType.tryFillFromExpr(methodParameters.get(0))) {
fieldName = childrenType.field;
isChildren = true;
}
Object spatialParamsObject = SpatialParamsFactory.generateSpatialParamsObject(methodName, methodParameters);
Condition condition = null;
if (isNested)
condition = new Condition(Where.CONN.valueOf(opear), fieldName,null, methodName, spatialParamsObject, null,nestedType);
else if (isChildren)
condition = new Condition(Where.CONN.valueOf(opear), fieldName,null, methodName, spatialParamsObject, null,childrenType);
else
condition = new Condition(Where.CONN.valueOf(opear), fieldName,null ,methodName, spatialParamsObject,null, null);
where.addWhere(condition);
} else if (methodName.toLowerCase().equals("nested")) {
NestedType nestedType = new NestedType();
if (!nestedType.tryFillFromExpr(expr)) {
throw new SqlParseException("could not fill nested from expr:" + expr);
}
Condition condition = new Condition(Where.CONN.valueOf(opear), nestedType.path,null, methodName.toUpperCase(), nestedType.where,null);
where.addWhere(condition);
} else if (methodName.toLowerCase().equals("children")) {
ChildrenType childrenType = new ChildrenType();
if (!childrenType.tryFillFromExpr(expr)) {
throw new SqlParseException("could not fill children from expr:" + expr);
}
Condition condition = new Condition(Where.CONN.valueOf(opear), childrenType.childType,null, methodName.toUpperCase(), childrenType.where,null);
where.addWhere(condition);
} else if (methodName.toLowerCase().equals("script")) {
ScriptFilter scriptFilter = new ScriptFilter();
if (!scriptFilter.tryParseFromMethodExpr(methodExpr)) {
throw new SqlParseException("could not parse script filter");
}
Condition condition = new Condition(Where.CONN.valueOf(opear), null, null,"SCRIPT", scriptFilter,null);
where.addWhere(condition);
} else {
throw new SqlParseException("unsupported method: " + methodName);
}
} else if (expr instanceof SQLInSubQueryExpr) {
SQLInSubQueryExpr sqlIn = (SQLInSubQueryExpr) expr;
Select innerSelect = sqlParser.parseSelect((MySqlSelectQueryBlock) sqlIn.getSubQuery().getQuery());
if (innerSelect.getFields() == null || innerSelect.getFields().size() != 1)
throw new SqlParseException("should only have one return field in subQuery");
SubQueryExpression subQueryExpression = new SubQueryExpression(innerSelect);
String leftSide = sqlIn.getExpr().toString();
boolean isNested = false;
boolean isChildren = false;
NestedType nestedType = new NestedType();
if (nestedType.tryFillFromExpr(sqlIn.getExpr())) {
leftSide = nestedType.field;
isNested = true;
}
ChildrenType childrenType = new ChildrenType();
if (childrenType.tryFillFromExpr(sqlIn.getExpr())) {
leftSide = childrenType.field;
isChildren = true;
}
Condition condition = null;
if (isNested)
condition = new Condition(Where.CONN.valueOf(opear), leftSide,null, sqlIn.isNot() ? "NOT IN" : "IN", subQueryExpression, null,nestedType);
else if (isChildren)
condition = new Condition(Where.CONN.valueOf(opear), leftSide,null, sqlIn.isNot() ? "NOT IN" : "IN", subQueryExpression, null, childrenType);
else
condition = new Condition(Where.CONN.valueOf(opear), leftSide,null, sqlIn.isNot() ? "NOT IN" : "IN", subQueryExpression, null, null);
where.addWhere(condition);
} else {
throw new SqlParseException("err find condition " + expr.getClass());
}
}
private MethodField parseSQLMethodInvokeExprWithFunctionInWhere(SQLMethodInvokeExpr soExpr) throws SqlParseException {
MethodField methodField = FieldMaker.makeMethodField(soExpr.getMethodName(),
soExpr.getParameters(),
null,
null,
query != null ? query.getFrom().getAlias() : null,
false);
return methodField;
}
private SQLMethodInvokeExpr parseSQLBinaryOpExprWhoIsConditionInWhere(SQLBinaryOpExpr soExpr) throws SqlParseException {
if (!(soExpr.getLeft() instanceof SQLMethodInvokeExpr ||
soExpr.getRight() instanceof SQLMethodInvokeExpr)) {
return null;
}
if (soExpr.getLeft() instanceof SQLMethodInvokeExpr) {
if (!SQLFunctions.buildInFunctions.contains(((SQLMethodInvokeExpr) soExpr.getLeft()).getMethodName())) {
return null;
}
}
if (soExpr.getRight() instanceof SQLMethodInvokeExpr) {
if (!SQLFunctions.buildInFunctions.contains(((SQLMethodInvokeExpr) soExpr.getRight()).getMethodName())) {
return null;
}
}
MethodField leftMethod = new MethodField(null, Lists.newArrayList(new KVValue("", Util.expr2Object(soExpr.getLeft(), "'"))), null, null);
MethodField rightMethod = new MethodField(null, Lists.newArrayList(new KVValue("", Util.expr2Object(soExpr.getRight(), "'"))), null, null);
if (soExpr.getLeft() instanceof SQLIdentifierExpr || soExpr.getLeft() instanceof SQLPropertyExpr) {
leftMethod = new MethodField(null, Lists.newArrayList(new KVValue("", "doc['" + Util.expr2Object(soExpr.getLeft(), "'") + "'].value")), null, null);
}
if (soExpr.getRight() instanceof SQLIdentifierExpr || soExpr.getRight() instanceof SQLPropertyExpr) {
rightMethod = new MethodField(null, Lists.newArrayList(new KVValue("", "doc['" + Util.expr2Object(soExpr.getRight(), "'") + "'].value")), null, null);
}
if (soExpr.getLeft() instanceof SQLMethodInvokeExpr) {
leftMethod = parseSQLMethodInvokeExprWithFunctionInWhere((SQLMethodInvokeExpr) soExpr.getLeft());
}
if (soExpr.getRight() instanceof SQLMethodInvokeExpr) {
rightMethod = parseSQLMethodInvokeExprWithFunctionInWhere((SQLMethodInvokeExpr) soExpr.getRight());
}
String v1 = leftMethod.getParams().get(0).value.toString();
String v1Dec = leftMethod.getParams().size() == 2 ? leftMethod.getParams().get(1).value.toString() + ";" : "";
String v2 = rightMethod.getParams().get(0).value.toString();
String v2Dec = rightMethod.getParams().size() == 2 ? rightMethod.getParams().get(1).value.toString() + ";" : "";
String operator = soExpr.getOperator().getName();
if (operator.equals("=")) {
operator = "==";
}
String finalStr = v1Dec + v2Dec + v1 + " " + operator + " " + v2;
SQLMethodInvokeExpr scriptMethod = new SQLMethodInvokeExpr("script", null);
scriptMethod.addParameter(new SQLCharExpr(finalStr));
return scriptMethod;
}
private Object[] getMethodValuesWithSubQueries(SQLMethodInvokeExpr method) throws SqlParseException {
List
© 2015 - 2025 Weber Informatics LLC | Privacy Policy