diff --git a/src/main/java/org/nlpcn/es4sql/Test.java b/src/main/java/org/nlpcn/es4sql/Test.java index 1a0e3976..7cae2ace 100644 --- a/src/main/java/org/nlpcn/es4sql/Test.java +++ b/src/main/java/org/nlpcn/es4sql/Test.java @@ -75,7 +75,7 @@ public static void main(String[] args) throws Exception { "group by key "; String TEST_INDEX = "elasticsearch-sql_test_index"; - sql = "select count(t.*) as counts,sum(t.size) from xxx/locs as t group by t.kk"; + sql = "select * from xxx/locs where 'a' = 'b' and a > 1"; System.out.println("sql" + sql + ":\n----------\n" + sqlToEsQuery(sql)); diff --git a/src/main/java/org/nlpcn/es4sql/Util.java b/src/main/java/org/nlpcn/es4sql/Util.java index eaec7ad3..98e3ebbe 100644 --- a/src/main/java/org/nlpcn/es4sql/Util.java +++ b/src/main/java/org/nlpcn/es4sql/Util.java @@ -49,11 +49,15 @@ public static Object removeTableAilasFromField(Object expr, String tableAlias) { public static Object expr2Object(SQLExpr expr) { + return expr2Object(expr, ""); + } + + public static Object expr2Object(SQLExpr expr, String charWithQuote) { Object value = null; if (expr instanceof SQLNumericLiteralExpr) { value = ((SQLNumericLiteralExpr) expr).getNumber(); } else if (expr instanceof SQLCharExpr) { - value = ((SQLCharExpr) expr).getText(); + value = charWithQuote + ((SQLCharExpr) expr).getText() + charWithQuote; } else if (expr instanceof SQLIdentifierExpr) { value = expr.toString(); } else if (expr instanceof SQLPropertyExpr) { diff --git a/src/main/java/org/nlpcn/es4sql/parse/SqlParser.java b/src/main/java/org/nlpcn/es4sql/parse/SqlParser.java index a3dfe37d..1f94bba1 100644 --- a/src/main/java/org/nlpcn/es4sql/parse/SqlParser.java +++ b/src/main/java/org/nlpcn/es4sql/parse/SqlParser.java @@ -19,28 +19,27 @@ /** * es sql support - * + * * @author ansj - * */ public class SqlParser { - public SqlParser() { - } + public SqlParser() { + } - public Select parseSelect(SQLQueryExpr mySqlExpr) throws SqlParseException { + public Select parseSelect(SQLQueryExpr mySqlExpr) throws SqlParseException { - MySqlSelectQueryBlock query = (MySqlSelectQueryBlock) mySqlExpr.getSubQuery().getQuery(); + MySqlSelectQueryBlock query = (MySqlSelectQueryBlock) mySqlExpr.getSubQuery().getQuery(); Select select = parseSelect(query); - return select; - } + return select; + } private Select parseSelect(MySqlSelectQueryBlock query) throws SqlParseException { Select select = new Select(); - findSelect(query, select,query.getFrom().getAlias()); + findSelect(query, select, query.getFrom().getAlias()); select.getFrom().addAll(findFrom(query.getFrom())); @@ -59,71 +58,96 @@ private Select parseSelect(MySqlSelectQueryBlock query) throws SqlParseException } public Delete parseDelete(SQLDeleteStatement deleteStatement) throws SqlParseException { - Delete delete = new Delete(); + Delete delete = new Delete(); - delete.getFrom().addAll(findFrom(deleteStatement.getTableSource())); + delete.getFrom().addAll(findFrom(deleteStatement.getTableSource())); - delete.setWhere(findWhere(deleteStatement.getWhere())); + delete.setWhere(findWhere(deleteStatement.getWhere())); - return delete; - } + return delete; + } - private Where findWhere(SQLExpr where) throws SqlParseException { - if(where == null) { - return null; - } + private Where findWhere(SQLExpr where) throws SqlParseException { + if (where == null) { + return null; + } - Where myWhere = Where.newInstance(); - parseWhere(where, myWhere); - return myWhere; - } + Where myWhere = Where.newInstance(); + parseWhere(where, myWhere); + return myWhere; + } - private boolean isCond(SQLBinaryOpExpr expr) { + private boolean isCond(SQLBinaryOpExpr expr) { SQLExpr leftSide = expr.getLeft(); - if(leftSide instanceof SQLMethodInvokeExpr){ - return isAllowedMethodOnConditionLeft((SQLMethodInvokeExpr) leftSide,expr.getOperator()); + if (leftSide instanceof SQLMethodInvokeExpr) { + return isAllowedMethodOnConditionLeft((SQLMethodInvokeExpr) leftSide, expr.getOperator()); } - return leftSide instanceof SQLIdentifierExpr || leftSide instanceof SQLPropertyExpr || leftSide instanceof SQLVariantRefExpr; - } + 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")) && !operator.isLogical(); + return (method.getMethodName().toLowerCase().equals("nested") || method.getMethodName().toLowerCase().equals("children")) && !operator.isLogical(); } public void parseWhere(SQLExpr expr, Where where) throws SqlParseException { - 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 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 && !isCond((SQLBinaryOpExpr) expr)) { + SQLBinaryOpExpr bExpr = (SQLBinaryOpExpr) expr; + if (explanSpecialCond(bExpr, where)) { + return; + } + 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); + } + } + + //some where conditions eg. 1=1 or 3>2 or 'a'='b' + private boolean explanSpecialCond(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; + } + + + 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; @@ -132,47 +156,47 @@ private void explanCond(String opear, SQLExpr expr, Where where) throws SqlParse boolean isChildren = false; NestedType nestedType = new NestedType(); - if(nestedType.tryFillFromExpr(soExpr.getLeft())){ + if (nestedType.tryFillFromExpr(soExpr.getLeft())) { soExpr.setLeft(new SQLIdentifierExpr(nestedType.field)); isNested = true; } ChildrenType childrenType = new ChildrenType(); - if(childrenType.tryFillFromExpr(soExpr.getLeft())){ + if (childrenType.tryFillFromExpr(soExpr.getLeft())) { soExpr.setLeft(new SQLIdentifierExpr(childrenType.field)); isChildren = true; } - if(soExpr.getRight() instanceof SQLMethodInvokeExpr){ + if (soExpr.getRight() instanceof SQLMethodInvokeExpr) { SQLMethodInvokeExpr method = (SQLMethodInvokeExpr) soExpr.getRight(); String methodName = method.getMethodName().toLowerCase(); - if(Condition.OPEAR.methodNameToOpear.containsKey(methodName)){ + if (Condition.OPEAR.methodNameToOpear.containsKey(methodName)) { Object[] methodParametersValue = getMethodValuesWithSubQueries(method); - Condition condition = null; + Condition condition = null; - if(isNested) - condition = new Condition(CONN.valueOf(opear) ,soExpr.getLeft().toString(), Condition.OPEAR.methodNameToOpear.get(methodName),methodParametersValue, nestedType); - else if(isChildren) - condition = new Condition(CONN.valueOf(opear) ,soExpr.getLeft().toString(), Condition.OPEAR.methodNameToOpear.get(methodName),methodParametersValue, childrenType); + if (isNested) + condition = new Condition(CONN.valueOf(opear), soExpr.getLeft().toString(), Condition.OPEAR.methodNameToOpear.get(methodName), methodParametersValue, nestedType); + else if (isChildren) + condition = new Condition(CONN.valueOf(opear), soExpr.getLeft().toString(), Condition.OPEAR.methodNameToOpear.get(methodName), methodParametersValue, childrenType); else - condition = new Condition(CONN.valueOf(opear) ,soExpr.getLeft().toString(), Condition.OPEAR.methodNameToOpear.get(methodName),methodParametersValue, null); + condition = new Condition(CONN.valueOf(opear), soExpr.getLeft().toString(), Condition.OPEAR.methodNameToOpear.get(methodName), methodParametersValue, null); where.addWhere(condition); methodAsOpear = true; } } - if(!methodAsOpear){ + if (!methodAsOpear) { Condition condition = null; - if(isNested) - condition = new Condition(CONN.valueOf(opear), soExpr.getLeft().toString(), soExpr.getOperator().name, parseValue(soExpr.getRight()), nestedType); - else if(isChildren) - condition = new Condition(CONN.valueOf(opear), soExpr.getLeft().toString(), soExpr.getOperator().name, parseValue(soExpr.getRight()), childrenType); + if (isNested) + condition = new Condition(CONN.valueOf(opear), soExpr.getLeft().toString(), soExpr.getOperator().name, parseValue(soExpr.getRight()), nestedType); + else if (isChildren) + condition = new Condition(CONN.valueOf(opear), soExpr.getLeft().toString(), soExpr.getOperator().name, parseValue(soExpr.getRight()), childrenType); else - condition = new Condition(CONN.valueOf(opear), soExpr.getLeft().toString(), soExpr.getOperator().name, parseValue(soExpr.getRight()), null); + condition = new Condition(CONN.valueOf(opear), soExpr.getLeft().toString(), soExpr.getOperator().name, parseValue(soExpr.getRight()), null); where.addWhere(condition); } @@ -184,27 +208,27 @@ else if(isChildren) boolean isChildren = false; NestedType nestedType = new NestedType(); - if(nestedType.tryFillFromExpr(siExpr.getExpr())){ + if (nestedType.tryFillFromExpr(siExpr.getExpr())) { leftSide = nestedType.field; isNested = false; } ChildrenType childrenType = new ChildrenType(); - if(childrenType.tryFillFromExpr(siExpr.getExpr())){ + if (childrenType.tryFillFromExpr(siExpr.getExpr())) { leftSide = childrenType.field; isChildren = true; } - Condition condition = null; + Condition condition = null; - if(isNested) - condition = new Condition(CONN.valueOf(opear), leftSide, siExpr.isNot() ? "NOT IN" : "IN", parseValue(siExpr.getTargetList()), nestedType); - else if(isChildren) - condition = new Condition(CONN.valueOf(opear), leftSide, siExpr.isNot() ? "NOT IN" : "IN", parseValue(siExpr.getTargetList()), childrenType); + if (isNested) + condition = new Condition(CONN.valueOf(opear), leftSide, siExpr.isNot() ? "NOT IN" : "IN", parseValue(siExpr.getTargetList()), nestedType); + else if (isChildren) + condition = new Condition(CONN.valueOf(opear), leftSide, siExpr.isNot() ? "NOT IN" : "IN", parseValue(siExpr.getTargetList()), childrenType); else - condition = new Condition(CONN.valueOf(opear), leftSide, siExpr.isNot() ? "NOT IN" : "IN", parseValue(siExpr.getTargetList()), null); + condition = new Condition(CONN.valueOf(opear), leftSide, siExpr.isNot() ? "NOT IN" : "IN", parseValue(siExpr.getTargetList()), null); where.addWhere(condition); } else if (expr instanceof SQLBetweenExpr) { @@ -215,53 +239,52 @@ else if(isChildren) boolean isChildren = false; NestedType nestedType = new NestedType(); - if(nestedType.tryFillFromExpr(between.getTestExpr())){ + if (nestedType.tryFillFromExpr(between.getTestExpr())) { leftSide = nestedType.field; - + isNested = true; } ChildrenType childrenType = new ChildrenType(); - if(childrenType.tryFillFromExpr(between.getTestExpr())){ + if (childrenType.tryFillFromExpr(between.getTestExpr())) { leftSide = childrenType.field; - + isChildren = true; } - Condition condition = null; - - if(isNested) - condition = new Condition(CONN.valueOf(opear), leftSide, between.isNot() ? "NOT BETWEEN" : "BETWEEN", new Object[]{parseValue(between.beginExpr), parseValue(between.endExpr)}, nestedType); - else if(isChildren) - condition = new Condition(CONN.valueOf(opear), leftSide, between.isNot() ? "NOT BETWEEN" : "BETWEEN", new Object[]{parseValue(between.beginExpr), parseValue(between.endExpr)}, childrenType); + Condition condition = null; + + if (isNested) + condition = new Condition(CONN.valueOf(opear), leftSide, between.isNot() ? "NOT BETWEEN" : "BETWEEN", new Object[]{parseValue(between.beginExpr), parseValue(between.endExpr)}, nestedType); + else if (isChildren) + condition = new Condition(CONN.valueOf(opear), leftSide, between.isNot() ? "NOT BETWEEN" : "BETWEEN", new Object[]{parseValue(between.beginExpr), parseValue(between.endExpr)}, childrenType); else - condition = new Condition(CONN.valueOf(opear), leftSide, between.isNot() ? "NOT BETWEEN" : "BETWEEN", new Object[]{parseValue(between.beginExpr), parseValue(between.endExpr)}, null); + condition = new Condition(CONN.valueOf(opear), leftSide, between.isNot() ? "NOT BETWEEN" : "BETWEEN", new Object[]{parseValue(between.beginExpr), parseValue(between.endExpr)}, null); where.addWhere(condition); - } - else if (expr instanceof SQLMethodInvokeExpr) { + } else if (expr instanceof SQLMethodInvokeExpr) { SQLMethodInvokeExpr methodExpr = (SQLMethodInvokeExpr) expr; List methodParameters = methodExpr.getParameters(); String methodName = methodExpr.getMethodName(); - if(SpatialParamsFactory.isAllowedMethod(methodName)){ + 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; } @@ -269,56 +292,52 @@ else if (expr instanceof SQLMethodInvokeExpr) { Condition condition = null; - if(isNested) - condition = new Condition(CONN.valueOf(opear), fieldName, methodName, spatialParamsObject, nestedType); - else if(isChildren) - condition = new Condition(CONN.valueOf(opear), fieldName, methodName, spatialParamsObject, childrenType); + if (isNested) + condition = new Condition(CONN.valueOf(opear), fieldName, methodName, spatialParamsObject, nestedType); + else if (isChildren) + condition = new Condition(CONN.valueOf(opear), fieldName, methodName, spatialParamsObject, childrenType); else - condition = new Condition(CONN.valueOf(opear), fieldName, methodName, spatialParamsObject, null); + condition = new Condition(CONN.valueOf(opear), fieldName, methodName, spatialParamsObject, null); where.addWhere(condition); - } - else if (methodName.toLowerCase().equals("nested")){ - NestedType nestedType = new NestedType(); + } else if (methodName.toLowerCase().equals("nested")) { + NestedType nestedType = new NestedType(); - if(!nestedType.tryFillFromExpr(expr)){ + if (!nestedType.tryFillFromExpr(expr)) { throw new SqlParseException("could not fill nested from expr:" + expr); } - Condition condition = new Condition(CONN.valueOf(opear), nestedType.path, methodName.toUpperCase(), nestedType.where); + Condition condition = new Condition(CONN.valueOf(opear), nestedType.path, methodName.toUpperCase(), nestedType.where); - where.addWhere(condition); - } - else if (methodName.toLowerCase().equals("children")){ - ChildrenType childrenType = new ChildrenType(); + where.addWhere(condition); + } else if (methodName.toLowerCase().equals("children")) { + ChildrenType childrenType = new ChildrenType(); - if(!childrenType.tryFillFromExpr(expr)){ + if (!childrenType.tryFillFromExpr(expr)) { throw new SqlParseException("could not fill children from expr:" + expr); } Condition condition = new Condition(CONN.valueOf(opear), childrenType.childType, methodName.toUpperCase(), childrenType.where); where.addWhere(condition); - } - else if (methodName.toLowerCase().equals("script")){ + } else if (methodName.toLowerCase().equals("script")) { ScriptFilter scriptFilter = new ScriptFilter(); - if(!scriptFilter.tryParseFromMethodExpr(methodExpr)){ + if (!scriptFilter.tryParseFromMethodExpr(methodExpr)) { throw new SqlParseException("could not parse script filter"); } - Condition condition = new Condition(CONN.valueOf(opear),null,"SCRIPT",scriptFilter); + Condition condition = new Condition(CONN.valueOf(opear), null, "SCRIPT", scriptFilter); where.addWhere(condition); - } - else { + } else { throw new SqlParseException("unsupported method: " + methodName); } - } else if (expr instanceof SQLInSubQueryExpr){ + } else if (expr instanceof SQLInSubQueryExpr) { SQLInSubQueryExpr sqlIn = (SQLInSubQueryExpr) expr; - + Select innerSelect = parseSelect((MySqlSelectQueryBlock) sqlIn.getSubQuery().getQuery()); - - if(innerSelect.getFields() == null || innerSelect.getFields().size()!=1) + + 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(); @@ -327,45 +346,43 @@ else if (methodName.toLowerCase().equals("script")){ boolean isChildren = false; NestedType nestedType = new NestedType(); - if(nestedType.tryFillFromExpr(sqlIn.getExpr())){ + if (nestedType.tryFillFromExpr(sqlIn.getExpr())) { leftSide = nestedType.field; - + isNested = true; } - + ChildrenType childrenType = new ChildrenType(); - if(childrenType.tryFillFromExpr(sqlIn.getExpr())){ + if (childrenType.tryFillFromExpr(sqlIn.getExpr())) { leftSide = childrenType.field; - + isChildren = true; } - Condition condition = null; + Condition condition = null; - if(isNested) - condition = new Condition(CONN.valueOf(opear), leftSide, sqlIn.isNot() ? "NOT IN" : "IN", subQueryExpression, nestedType); - else if(isChildren) - condition = new Condition(CONN.valueOf(opear), leftSide, sqlIn.isNot() ? "NOT IN" : "IN", subQueryExpression, childrenType); + if (isNested) + condition = new Condition(CONN.valueOf(opear), leftSide, sqlIn.isNot() ? "NOT IN" : "IN", subQueryExpression, nestedType); + else if (isChildren) + condition = new Condition(CONN.valueOf(opear), leftSide, sqlIn.isNot() ? "NOT IN" : "IN", subQueryExpression, childrenType); else - condition = new Condition(CONN.valueOf(opear), leftSide, sqlIn.isNot() ? "NOT IN" : "IN", subQueryExpression, null); + condition = new Condition(CONN.valueOf(opear), leftSide, sqlIn.isNot() ? "NOT IN" : "IN", subQueryExpression, null); where.addWhere(condition); } else { - throw new SqlParseException("err find condition " + expr.getClass()); - } - } + throw new SqlParseException("err find condition " + expr.getClass()); + } + } private Object[] getMethodValuesWithSubQueries(SQLMethodInvokeExpr method) throws SqlParseException { List values = new ArrayList<>(); - for(SQLExpr innerExpr : method.getParameters()){ - if(innerExpr instanceof SQLQueryExpr){ + for (SQLExpr innerExpr : method.getParameters()) { + if (innerExpr instanceof SQLQueryExpr) { Select select = parseSelect((MySqlSelectQueryBlock) ((SQLQueryExpr) innerExpr).getSubQuery().getQuery()); values.add(new SubQueryExpression(select)); - } - else if(innerExpr instanceof SQLTextLiteralExpr){ - values.add(((SQLTextLiteralExpr)innerExpr).getText()); - } - else { + } else if (innerExpr instanceof SQLTextLiteralExpr) { + values.add(((SQLTextLiteralExpr) innerExpr).getText()); + } else { values.add(innerExpr); } @@ -374,127 +391,126 @@ else if(innerExpr instanceof SQLTextLiteralExpr){ } private Object[] parseValue(List targetList) throws SqlParseException { - Object[] value = new Object[targetList.size()]; - for (int i = 0; i < targetList.size(); i++) { - value[i] = parseValue(targetList.get(i)); - } - return value; - } - - private Object parseValue(SQLExpr expr) throws SqlParseException { - if (expr instanceof SQLNumericLiteralExpr) { - return ((SQLNumericLiteralExpr) expr).getNumber(); - } else if (expr instanceof SQLCharExpr) { - return ((SQLCharExpr) expr).getText(); - } else if (expr instanceof SQLMethodInvokeExpr) { - return expr; - } else if (expr instanceof SQLNullExpr) { - return null; - } else if (expr instanceof SQLIdentifierExpr) { + Object[] value = new Object[targetList.size()]; + for (int i = 0; i < targetList.size(); i++) { + value[i] = parseValue(targetList.get(i)); + } + return value; + } + + private Object parseValue(SQLExpr expr) throws SqlParseException { + if (expr instanceof SQLNumericLiteralExpr) { + return ((SQLNumericLiteralExpr) expr).getNumber(); + } else if (expr instanceof SQLCharExpr) { + return ((SQLCharExpr) expr).getText(); + } else if (expr instanceof SQLMethodInvokeExpr) { return expr; - } else if (expr instanceof SQLPropertyExpr){ + } else if (expr instanceof SQLNullExpr) { + return null; + } else if (expr instanceof SQLIdentifierExpr) { return expr; - } else { - throw new SqlParseException( - String.format("Failed to parse SqlExpression of type %s. expression value: %s", expr.getClass(), expr) - ); - } - } + } else if (expr instanceof SQLPropertyExpr) { + return expr; + } else { + throw new SqlParseException( + String.format("Failed to parse SqlExpression of type %s. expression value: %s", expr.getClass(), expr) + ); + } + } - private void findSelect(MySqlSelectQueryBlock query, Select select,String tableAlias) throws SqlParseException { + private void findSelect(MySqlSelectQueryBlock query, Select select, String tableAlias) throws SqlParseException { List selectList = query.getSelectList(); for (SQLSelectItem sqlSelectItem : selectList) { - Field field = FieldMaker.makeField(sqlSelectItem.getExpr(), sqlSelectItem.getAlias(),tableAlias); + Field field = FieldMaker.makeField(sqlSelectItem.getExpr(), sqlSelectItem.getAlias(), tableAlias); select.addField(field); } } - private void findGroupBy(MySqlSelectQueryBlock query, Select select) throws SqlParseException { - SQLSelectGroupByClause groupBy = query.getGroupBy(); + private void findGroupBy(MySqlSelectQueryBlock query, Select select) throws SqlParseException { + SQLSelectGroupByClause groupBy = query.getGroupBy(); SQLTableSource sqlTableSource = query.getFrom(); - if (groupBy == null) { - return; - } - List items = groupBy.getItems(); + if (groupBy == null) { + return; + } + List items = groupBy.getItems(); - List standardGroupBys = new ArrayList<>(); - for (SQLExpr sqlExpr : items) { + List standardGroupBys = new ArrayList<>(); + for (SQLExpr sqlExpr : items) { //todo: mysql expr patch if (sqlExpr instanceof MySqlSelectGroupByExpr) { MySqlSelectGroupByExpr sqlSelectGroupByExpr = (MySqlSelectGroupByExpr) sqlExpr; sqlExpr = sqlSelectGroupByExpr.getExpr(); } - if ((sqlExpr instanceof SQLParensIdentifierExpr || !(sqlExpr instanceof SQLIdentifierExpr|| sqlExpr instanceof SQLMethodInvokeExpr)) && !standardGroupBys.isEmpty()) { + if ((sqlExpr instanceof SQLParensIdentifierExpr || !(sqlExpr instanceof SQLIdentifierExpr || sqlExpr instanceof SQLMethodInvokeExpr)) && !standardGroupBys.isEmpty()) { // flush the standard group bys - select.addGroupBy(convertExprsToFields(standardGroupBys,sqlTableSource)); + select.addGroupBy(convertExprsToFields(standardGroupBys, sqlTableSource)); standardGroupBys = new ArrayList<>(); } - if (sqlExpr instanceof SQLParensIdentifierExpr) { + if (sqlExpr instanceof SQLParensIdentifierExpr) { // single item with parens (should get its own aggregation) - select.addGroupBy(FieldMaker.makeField(sqlExpr, null,sqlTableSource.getAlias())); + select.addGroupBy(FieldMaker.makeField(sqlExpr, null, sqlTableSource.getAlias())); } else if (sqlExpr instanceof SQLListExpr) { - // multiple items in their own list - SQLListExpr listExpr = (SQLListExpr) sqlExpr; - select.addGroupBy(convertExprsToFields(listExpr.getItems(),sqlTableSource)); - } else { - // everything else gets added to the running list of standard group bys - standardGroupBys.add(sqlExpr); - } - } - if (!standardGroupBys.isEmpty()) { - select.addGroupBy(convertExprsToFields(standardGroupBys,sqlTableSource)); - } - } - - private List convertExprsToFields(List exprs,SQLTableSource sqlTableSource) throws SqlParseException { - List fields = new ArrayList<>(exprs.size()); - for (SQLExpr expr : exprs) { + // multiple items in their own list + SQLListExpr listExpr = (SQLListExpr) sqlExpr; + select.addGroupBy(convertExprsToFields(listExpr.getItems(), sqlTableSource)); + } else { + // everything else gets added to the running list of standard group bys + standardGroupBys.add(sqlExpr); + } + } + if (!standardGroupBys.isEmpty()) { + select.addGroupBy(convertExprsToFields(standardGroupBys, sqlTableSource)); + } + } + + private List convertExprsToFields(List exprs, SQLTableSource sqlTableSource) throws SqlParseException { + List fields = new ArrayList<>(exprs.size()); + for (SQLExpr expr : exprs) { //here we suppose groupby field will not have alias,so set null in second parameter - fields.add(FieldMaker.makeField(expr, null,sqlTableSource.getAlias())); - } - return fields; - } + fields.add(FieldMaker.makeField(expr, null, sqlTableSource.getAlias())); + } + return fields; + } private String sameAliasWhere(Where where, String... aliases) throws SqlParseException { - if(where == null) return null; + if (where == null) return null; - if(where instanceof Condition) - { + if (where instanceof Condition) { Condition condition = (Condition) where; String fieldName = condition.getName(); - for (String alias : aliases){ + for (String alias : aliases) { String prefix = alias + "."; - if(fieldName.startsWith(prefix)){ + if (fieldName.startsWith(prefix)) { return alias; } } throw new SqlParseException(String.format("fieldName : %s on codition:%s does not contain alias", fieldName, condition.toString())); } List sameAliases = new ArrayList<>(); - if(where.getWheres()!=null && where.getWheres().size() > 0) { + if (where.getWheres() != null && where.getWheres().size() > 0) { for (Where innerWhere : where.getWheres()) sameAliases.add(sameAliasWhere(innerWhere, aliases)); } - if ( sameAliases.contains(null) ) return null; + if (sameAliases.contains(null)) return null; String firstAlias = sameAliases.get(0); //return null if more than one alias - for(String alias : sameAliases){ - if(!alias.equals(firstAlias)) return null; + for (String alias : sameAliases) { + if (!alias.equals(firstAlias)) return null; } return firstAlias; } - private void findOrderBy(MySqlSelectQueryBlock query, Select select) throws SqlParseException { - SQLOrderBy orderBy = query.getOrderBy(); + private void findOrderBy(MySqlSelectQueryBlock query, Select select) throws SqlParseException { + SQLOrderBy orderBy = query.getOrderBy(); - if (orderBy == null) { - return; - } - List items = orderBy.getItems(); + if (orderBy == null) { + return; + } + List items = orderBy.getItems(); addOrderByToSelect(select, items, null); @@ -511,7 +527,7 @@ private void addOrderByToSelect(Select select, List items, String type = sqlSelectOrderByItem.getType().toString(); orderByName = orderByName.replace("`", ""); - if(alias!=null) orderByName = orderByName.replaceFirst(alias+"\\.",""); + if (alias != null) orderByName = orderByName.replaceFirst(alias + "\\.", ""); select.addOrderBy(orderByName, type); } @@ -519,31 +535,32 @@ private void addOrderByToSelect(Select select, List items, private void findLimit(MySqlSelectQueryBlock.Limit limit, Select select) { - if (limit == null) { - return; - } + if (limit == null) { + return; + } - select.setRowCount(Integer.parseInt(limit.getRowCount().toString())); + select.setRowCount(Integer.parseInt(limit.getRowCount().toString())); - if (limit.getOffset() != null) - select.setOffset(Integer.parseInt(limit.getOffset().toString())); - } + if (limit.getOffset() != null) + select.setOffset(Integer.parseInt(limit.getOffset().toString())); + } - /** - * Parse the from clause - * @param from the from clause. - * @return list of From objects represents all the sources. - */ - private List findFrom(SQLTableSource from) { + /** + * Parse the from clause + * + * @param from the from clause. + * @return list of From objects represents all the sources. + */ + private List findFrom(SQLTableSource from) { boolean isSqlExprTable = from.getClass().isAssignableFrom(SQLExprTableSource.class); - if(isSqlExprTable){ + if (isSqlExprTable) { SQLExprTableSource fromExpr = (SQLExprTableSource) from; String[] split = fromExpr.getExpr().toString().split(","); ArrayList fromList = new ArrayList<>(); for (String source : split) { - fromList.add(new From(source.trim(),fromExpr.getAlias())); + fromList.add(new From(source.trim(), fromExpr.getAlias())); } return fromList; } @@ -560,7 +577,7 @@ public JoinSelect parseJoinSelect(SQLQueryExpr sqlExpr) throws SqlParseException MySqlSelectQueryBlock query = (MySqlSelectQueryBlock) sqlExpr.getSubQuery().getQuery(); List joinedFrom = findJoinedFrom(query.getFrom()); - if(joinedFrom.size() != 2) + if (joinedFrom.size() != 2) throw new RuntimeException("currently supports only 2 tables join"); JoinSelect joinSelect = createBasicJoinSelectAccordingToTableSource((SQLJoinTableSource) query.getFrom()); @@ -572,8 +589,8 @@ public JoinSelect parseJoinSelect(SQLQueryExpr sqlExpr) throws SqlParseException Map> aliasToOrderBy = splitAndFindOrder(query.getOrderBy(), firstTableAlias, secondTableAlias); List connectedConditions = getConditionsFlatten(joinSelect.getConnectedWhere()); joinSelect.setConnectedConditions(connectedConditions); - fillTableSelectedJoin(joinSelect.getFirstTable(), query, joinedFrom.get(0), aliasToWhere.get(firstTableAlias),aliasToOrderBy.get(firstTableAlias), connectedConditions); - fillTableSelectedJoin(joinSelect.getSecondTable(), query, joinedFrom.get(1), aliasToWhere.get(secondTableAlias), aliasToOrderBy.get(secondTableAlias),connectedConditions); + fillTableSelectedJoin(joinSelect.getFirstTable(), query, joinedFrom.get(0), aliasToWhere.get(firstTableAlias), aliasToOrderBy.get(firstTableAlias), connectedConditions); + fillTableSelectedJoin(joinSelect.getSecondTable(), query, joinedFrom.get(1), aliasToWhere.get(secondTableAlias), aliasToOrderBy.get(secondTableAlias), connectedConditions); updateJoinLimit(query.getLimit(), joinSelect); @@ -582,19 +599,17 @@ public JoinSelect parseJoinSelect(SQLQueryExpr sqlExpr) throws SqlParseException } private Map> splitAndFindOrder(SQLOrderBy orderBy, String firstTableAlias, String secondTableAlias) throws SqlParseException { - Map> aliasToOrderBys = new HashMap<>(); - aliasToOrderBys.put(firstTableAlias,new ArrayList()); - aliasToOrderBys.put(secondTableAlias,new ArrayList()); - if(orderBy == null) return aliasToOrderBys; + Map> aliasToOrderBys = new HashMap<>(); + aliasToOrderBys.put(firstTableAlias, new ArrayList()); + aliasToOrderBys.put(secondTableAlias, new ArrayList()); + if (orderBy == null) return aliasToOrderBys; List orderByItems = orderBy.getItems(); - for(SQLSelectOrderByItem orderByItem : orderByItems){ - if(orderByItem.getExpr().toString().startsWith(firstTableAlias+".")){ + for (SQLSelectOrderByItem orderByItem : orderByItems) { + if (orderByItem.getExpr().toString().startsWith(firstTableAlias + ".")) { aliasToOrderBys.get(firstTableAlias).add(orderByItem); - } - else if(orderByItem.getExpr().toString().startsWith(secondTableAlias+".")){ + } else if (orderByItem.getExpr().toString().startsWith(secondTableAlias + ".")) { aliasToOrderBys.get(secondTableAlias).add(orderByItem); - } - else + } else throw new SqlParseException("order by field on join request should have alias before, got " + orderByItem.getExpr().toString()); } @@ -602,10 +617,10 @@ else if(orderByItem.getExpr().toString().startsWith(secondTableAlias+".")){ } private void updateJoinLimit(MySqlSelectQueryBlock.Limit limit, JoinSelect joinSelect) { - if(limit != null && limit.getRowCount()!= null) { - int sizeLimit = Integer.parseInt(limit.getRowCount().toString()); - joinSelect.setTotalLimit(sizeLimit); - } + if (limit != null && limit.getRowCount() != null) { + int sizeLimit = Integer.parseInt(limit.getRowCount().toString()); + joinSelect.setTotalLimit(sizeLimit); + } } private List parseHints(List sqlHints) throws SqlParseException { @@ -619,7 +634,7 @@ private List parseHints(List sqlHints) throws SqlParseExce private JoinSelect createBasicJoinSelectAccordingToTableSource(SQLJoinTableSource joinTableSource) throws SqlParseException { JoinSelect joinSelect = new JoinSelect(); - if(joinTableSource.getCondition() != null ) { + if (joinTableSource.getCondition() != null) { Where where = Where.newInstance(); parseWhere(joinTableSource.getCondition(), where); joinSelect.setConnectedWhere(where); @@ -636,7 +651,7 @@ private Map splitAndFindWhere(SQLExpr whereExpr, String firstTabl private void fillTableSelectedJoin(TableOnJoinSelect tableOnJoin, MySqlSelectQueryBlock query, From tableFrom, Where where, List orderBys, List conditions) throws SqlParseException { String alias = tableFrom.getAlias(); - fillBasicTableSelectJoin(tableOnJoin, tableFrom, where,orderBys, query); + fillBasicTableSelectJoin(tableOnJoin, tableFrom, where, orderBys, query); tableOnJoin.setConnectedFields(getConnectedFields(conditions, alias)); tableOnJoin.setSelectedFields(new ArrayList(tableOnJoin.getFields())); tableOnJoin.setAlias(alias); @@ -646,19 +661,18 @@ private void fillTableSelectedJoin(TableOnJoinSelect tableOnJoin, MySqlSelectQue private List getConnectedFields(List conditions, String alias) throws SqlParseException { List fields = new ArrayList<>(); String prefix = alias + "."; - for(Condition condition : conditions) { - if(condition.getName().startsWith(prefix)){ - fields.add(new Field(condition.getName().replaceFirst(prefix,""),null)); - } - else { - if(! ((condition.getValue() instanceof SQLPropertyExpr)||(condition.getValue() instanceof SQLIdentifierExpr)||(condition.getValue() instanceof String))){ + for (Condition condition : conditions) { + if (condition.getName().startsWith(prefix)) { + fields.add(new Field(condition.getName().replaceFirst(prefix, ""), null)); + } else { + if (!((condition.getValue() instanceof SQLPropertyExpr) || (condition.getValue() instanceof SQLIdentifierExpr) || (condition.getValue() instanceof String))) { throw new SqlParseException("conditions on join should be one side is firstTable second Other , condition was:" + condition.toString()); } String aliasDotValue = condition.getValue().toString(); int indexOfDot = aliasDotValue.indexOf("."); String owner = aliasDotValue.substring(0, indexOfDot); - if(owner.equals(alias)) - fields.add(new Field(aliasDotValue.substring(indexOfDot+1),null)); + if (owner.equals(alias)) + fields.add(new Field(aliasDotValue.substring(indexOfDot + 1), null)); } } return fields; @@ -666,14 +680,14 @@ private List getConnectedFields(List conditions, String alias) private void fillBasicTableSelectJoin(TableOnJoinSelect select, From from, Where where, List orderBys, MySqlSelectQueryBlock query) throws SqlParseException { select.getFrom().add(from); - findSelect(query, select,from.getAlias()); + findSelect(query, select, from.getAlias()); select.setWhere(where); - addOrderByToSelect(select, orderBys,from.getAlias()); + addOrderByToSelect(select, orderBys, from.getAlias()); } private List getJoinConditionsFlatten(SQLJoinTableSource from) throws SqlParseException { List conditions = new ArrayList<>(); - if(from.getCondition() == null ) return conditions; + if (from.getCondition() == null) return conditions; Where where = Where.newInstance(); parseWhere(from.getCondition(), where); addIfConditionRecursive(where, conditions); @@ -682,71 +696,68 @@ private List getJoinConditionsFlatten(SQLJoinTableSource from) throws private List getConditionsFlatten(Where where) throws SqlParseException { List conditions = new ArrayList<>(); - if(where == null) return conditions; + if (where == null) return conditions; addIfConditionRecursive(where, conditions); return conditions; } - private Map splitWheres(Where where, String... aliases) throws SqlParseException { - Map aliasToWhere = new HashMap<>(); - for(String alias : aliases){ - aliasToWhere.put(alias,null); + private Map splitWheres(Where where, String... aliases) throws SqlParseException { + Map aliasToWhere = new HashMap<>(); + for (String alias : aliases) { + aliasToWhere.put(alias, null); } - if(where == null) return aliasToWhere; + if (where == null) return aliasToWhere; String allWhereFromSameAlias = sameAliasWhere(where, aliases); - if( allWhereFromSameAlias != null ) { - removeAliasPrefix(where,allWhereFromSameAlias); - aliasToWhere.put(allWhereFromSameAlias,where); + if (allWhereFromSameAlias != null) { + removeAliasPrefix(where, allWhereFromSameAlias); + aliasToWhere.put(allWhereFromSameAlias, where); return aliasToWhere; } - for(Where innerWhere : where.getWheres()){ - String sameAlias = sameAliasWhere(innerWhere, aliases); - if(sameAlias == null ) + for (Where innerWhere : where.getWheres()) { + String sameAlias = sameAliasWhere(innerWhere, aliases); + if (sameAlias == null) throw new SqlParseException("Currently support only one hierarchy on different tables where"); - removeAliasPrefix(innerWhere,sameAlias); + removeAliasPrefix(innerWhere, sameAlias); Where aliasCurrentWhere = aliasToWhere.get(sameAlias); - if(aliasCurrentWhere == null) { + if (aliasCurrentWhere == null) { aliasToWhere.put(sameAlias, innerWhere); - } - else { + } else { Where andWhereContainer = Where.newInstance(); andWhereContainer.addWhere(aliasCurrentWhere); andWhereContainer.addWhere(innerWhere); - aliasToWhere.put(sameAlias,andWhereContainer); + aliasToWhere.put(sameAlias, andWhereContainer); } } - return aliasToWhere; + return aliasToWhere; } private void removeAliasPrefix(Where where, String alias) { - if(where instanceof Condition) { + if (where instanceof Condition) { Condition cond = (Condition) where; String fieldName = cond.getName(); String aliasPrefix = alias + "."; cond.setName(cond.getName().replaceFirst(aliasPrefix, "")); return; } - for(Where innerWhere : where.getWheres()) - { + for (Where innerWhere : where.getWheres()) { removeAliasPrefix(innerWhere, alias); } } private void addIfConditionRecursive(Where where, List conditions) throws SqlParseException { - if(where instanceof Condition){ + if (where instanceof Condition) { Condition cond = (Condition) where; - if( ! ((cond.getValue() instanceof SQLIdentifierExpr) ||(cond.getValue() instanceof SQLPropertyExpr)|| (cond.getValue() instanceof String))){ + if (!((cond.getValue() instanceof SQLIdentifierExpr) || (cond.getValue() instanceof SQLPropertyExpr) || (cond.getValue() instanceof String))) { throw new SqlParseException("conditions on join should be one side is secondTable OPEAR firstTable, condition was:" + cond.toString()); } conditions.add(cond); } - for(Where innerWhere : where.getWheres()) - { - addIfConditionRecursive(innerWhere,conditions); + for (Where innerWhere : where.getWheres()) { + addIfConditionRecursive(innerWhere, conditions); } } @@ -758,16 +769,16 @@ private List findJoinedFrom(SQLTableSource from) { return fromList; } - 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); - } + 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()); - } - } + } + } } diff --git a/src/test/java/org/nlpcn/es4sql/SqlParserTests.java b/src/test/java/org/nlpcn/es4sql/SqlParserTests.java index f8bd34d5..7a1189e5 100644 --- a/src/test/java/org/nlpcn/es4sql/SqlParserTests.java +++ b/src/test/java/org/nlpcn/es4sql/SqlParserTests.java @@ -538,7 +538,7 @@ public void nestedFieldOnWhereNoPathComplexField() throws SqlParseException { Assert.assertEquals("message.moreNested", condition.getNestedPath()); Assert.assertEquals("message.moreNested.name", condition.getName()); } - + @Test public void aggFieldWithAliasTableAliasShouldBeRemoved() throws SqlParseException { @@ -796,6 +796,57 @@ public void complexNestedAndOtherQuery() throws SqlParseException { Assert.assertEquals("AND y EQ 3", wheres.get(1).toString()); } + + @Test + public void numberEqualConditionWithoutProperty() throws SqlParseException { + SQLExpr sqlExpr = queryToExpr("select * from xxx/locs where 1 = 1"); + Select select = parser.parseSelect((SQLQueryExpr) sqlExpr); + List wheres = select.getWhere().getWheres(); + Assert.assertTrue(wheres.size()==1); + Condition condition = (Condition)wheres.get(0); + Assert.assertTrue(condition.getValue() instanceof ScriptFilter); + ScriptFilter sf = (ScriptFilter)condition.getValue(); + Assert.assertEquals(sf.getScript(),"1 == 1"); + } + + @Test + public void numberGreatConditionWithoutProperty() throws SqlParseException { + SQLExpr sqlExpr = queryToExpr("select * from xxx/locs where 1 > 1"); + Select select = parser.parseSelect((SQLQueryExpr) sqlExpr); + List wheres = select.getWhere().getWheres(); + Assert.assertTrue(wheres.size()==1); + Condition condition = (Condition)wheres.get(0); + Assert.assertTrue(condition.getValue() instanceof ScriptFilter); + ScriptFilter sf = (ScriptFilter)condition.getValue(); + Assert.assertEquals(sf.getScript(),"1 > 1"); + } + + @Test + public void stringEqualConditionWithoutProperty() throws SqlParseException { + SQLExpr sqlExpr = queryToExpr("select * from xxx/locs where 'a' = 'b'"); + Select select = parser.parseSelect((SQLQueryExpr) sqlExpr); + List wheres = select.getWhere().getWheres(); + Assert.assertTrue(wheres.size()==1); + Condition condition = (Condition)wheres.get(0); + Assert.assertTrue(condition.getValue() instanceof ScriptFilter); + ScriptFilter sf = (ScriptFilter)condition.getValue(); + Assert.assertEquals(sf.getScript(),"'a' == 'b'"); + } + + @Test + public void stringAndNumberEqualConditionWithoutProperty() throws SqlParseException { + SQLExpr sqlExpr = queryToExpr("select * from xxx/locs where 'a' = 1"); + Select select = parser.parseSelect((SQLQueryExpr) sqlExpr); + List wheres = select.getWhere().getWheres(); + Assert.assertTrue(wheres.size()==1); + Condition condition = (Condition)wheres.get(0); + Assert.assertTrue(condition.getValue() instanceof ScriptFilter); + ScriptFilter sf = (ScriptFilter)condition.getValue(); + Assert.assertEquals(sf.getScript(),"'a' == 1"); + } + + + private SQLExpr queryToExpr(String query) { return new ElasticSqlExprParser(query).expr(); }