Search in sources :

Example 61 with SQLNonTransientException

use of java.sql.SQLNonTransientException in project Mycat-Server by MyCATApache.

the class FunctionParser method parseFunction.

public static Function parseFunction(String function) throws SQLNonTransientException {
    StringBuilder buffer = new StringBuilder();
    Stack<Function> functions = new Stack<>();
    int flag = 0;
    for (int i = 0; i < function.length(); i++) {
        char current = function.charAt(i);
        switch(current) {
            case Commons.LEFT_BRACKET:
                if (flag == 0) {
                    String currentIdentifier = buffer.toString().trim();
                    buffer = new StringBuilder();
                    if (!StringUtil.isEmpty(currentIdentifier)) {
                        Function function1 = new Function(currentIdentifier);
                        if (!functions.empty() && functions.peek() != null) {
                            functions.peek().getArguments().add(function1);
                        }
                        functions.push(function1);
                    }
                    break;
                }
                buffer.append(current);
                break;
            case Commons.ARGUMENT_SEPARATOR:
                if (flag == 0 || flag == 3) {
                    String currentIdentifier = buffer.toString().trim();
                    buffer = new StringBuilder();
                    if (!StringUtil.isEmpty(currentIdentifier)) {
                        if (flag == 3) {
                            flag = 0;
                            Identifier identifier = new Identifier(currentIdentifier);
                            functions.peek().getArguments().add(identifier);
                        } else {
                            Field field = new Field(currentIdentifier);
                            functions.peek().getArguments().add(field);
                        }
                    }
                    break;
                }
                buffer.append(current);
                break;
            case Commons.RIGHT_BRACKET:
                if (flag != 1 && flag != 2) {
                    String currentIdentifier = buffer.toString().trim();
                    buffer = new StringBuilder();
                    if (!StringUtil.isEmpty(currentIdentifier)) {
                        if (flag == 3) {
                            flag = 0;
                            Identifier identifier = new Identifier(currentIdentifier);
                            functions.peek().getArguments().add(identifier);
                        } else {
                            Field field = new Field(currentIdentifier);
                            functions.peek().getArguments().add(field);
                        }
                    }
                    if (flag == 0) {
                        if (functions.size() == 1) {
                            return functions.pop();
                        } else {
                            functions.pop();
                        }
                    }
                    break;
                }
                buffer.append(current);
                break;
            case Commons.QUOTE:
                if (flag == 0) {
                    flag = 1;
                } else if (flag == 1) {
                    flag = 3;
                }
            case Commons.DOUBLE_QUOTE:
                if (flag == 0) {
                    flag = 2;
                } else if (flag == 2) {
                    flag = 3;
                }
            default:
                buffer.append(current);
        }
    }
    throw new SQLNonTransientException("Function is not in right format!");
}
Also used : Function(io.mycat.route.parser.primitive.Model.Function) Field(io.mycat.route.parser.primitive.Model.Field) SQLNonTransientException(java.sql.SQLNonTransientException) Identifier(io.mycat.route.parser.primitive.Model.Identifier) Stack(java.util.Stack)

Example 62 with SQLNonTransientException

use of java.sql.SQLNonTransientException in project Mycat-Server by MyCATApache.

the class DruidLockTableParser method statementParse.

@Override
public void statementParse(SchemaConfig schema, RouteResultset rrs, SQLStatement stmt) throws SQLNonTransientException {
    MySqlLockTableStatement lockTableStat = (MySqlLockTableStatement) stmt;
    String table = lockTableStat.getTableSource().toString().toUpperCase();
    TableConfig tableConfig = schema.getTables().get(table);
    if (tableConfig == null) {
        String msg = "can't find table define of " + table + " in schema:" + schema.getName();
        LOGGER.warn(msg);
        throw new SQLNonTransientException(msg);
    }
    LockType lockType = lockTableStat.getLockType();
    if (LockType.WRITE != lockType && LockType.READ != lockType) {
        String msg = "lock type must be write or read";
        LOGGER.warn(msg);
        throw new SQLNonTransientException(msg);
    }
    List<String> dataNodes = tableConfig.getDataNodes();
    RouteResultsetNode[] nodes = new RouteResultsetNode[dataNodes.size()];
    for (int i = 0; i < dataNodes.size(); i++) {
        nodes[i] = new RouteResultsetNode(dataNodes.get(i), ServerParse.LOCK, stmt.toString());
    }
    rrs.setNodes(nodes);
    rrs.setFinishedRoute(true);
}
Also used : SQLNonTransientException(java.sql.SQLNonTransientException) MySqlLockTableStatement(com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlLockTableStatement) RouteResultsetNode(io.mycat.route.RouteResultsetNode) TableConfig(io.mycat.config.model.TableConfig) LockType(com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlLockTableStatement.LockType)

Example 63 with SQLNonTransientException

use of java.sql.SQLNonTransientException in project Mycat-Server by MyCATApache.

the class DruidUpdateParser method shardColCanBeUpdated.

/*
    * 遍历where子句的AST,寻找是否有与update子句中更新分片字段相同的条件,
    * o 如果发现有or或者xor,然后分片字段的条件在or或者xor中的,这种情况update也无法执行,比如
    *   update mytab set ptn_col = val, col1 = val1 where col1 = val11 or ptn_col = val;
    *   但是下面的这种update是可以执行的
    *   update mytab set ptn_col = val, col1 = val1 where ptn_col = val and (col1 = val11 or col2 = val2);
    * o 如果没有发现与update子句中更新分片字段相同的条件,则update也无法执行,比如
    *   update mytab set ptn_col = val, col1 = val1 where col1 = val11 and col2 = val22;
    * o 如果条件之间都是and,且有与更新分片字段相同的条件,这种情况是允许执行的。比如
    *   update mytab set ptn_col = val, col1 = val1 where ptn_col = val and col1 = val11 and col2 = val2;
    * o 对于一些特殊的运算符,比如between,not,或者子查询,遇到这些子句现在不会去检查分片字段是否在此类子句中,
    *  即使分片字段在此类子句中,现在也认为对应的update语句无法执行。
    *
    * @param whereClauseExpr   where子句的语法树AST
    * @param column   分片字段的名字
    * @param value    分片字段要被更新成的值
    * @hasOR          遍历到whereClauseExpr这个节点的时候,其上层路径中是否有OR/XOR关系运算
    *
    * @return         true,表示update不能执行,false表示可以执行
    */
private boolean shardColCanBeUpdated(SQLExpr whereClauseExpr, String column, SQLExpr value, boolean hasOR) throws SQLNonTransientException {
    boolean canUpdate = false;
    boolean parentHasOR = false;
    if (whereClauseExpr == null)
        return false;
    if (whereClauseExpr instanceof SQLBinaryOpExpr) {
        SQLBinaryOpExpr nodeOpExpr = (SQLBinaryOpExpr) whereClauseExpr;
        /*
            * 条件中有or或者xor的,如果分片字段出现在or/xor的一个子句中,则此update
            * 语句无法执行
             */
        if ((nodeOpExpr.getOperator() == SQLBinaryOperator.BooleanOr) || (nodeOpExpr.getOperator() == SQLBinaryOperator.BooleanXor)) {
            parentHasOR = true;
        }
        // 发现类似 col = value 的子句
        if (nodeOpExpr.getOperator() == SQLBinaryOperator.Equality) {
            boolean foundCol;
            SQLExpr leftExpr = nodeOpExpr.getLeft();
            SQLExpr rightExpr = nodeOpExpr.getRight();
            foundCol = columnInExpr(leftExpr, column);
            // 发现col = value子句,col刚好是分片字段,比较value与update要更新的值是否一样,并且是否在or/xor子句中
            if (foundCol) {
                if (rightExpr.getClass() != value.getClass()) {
                    throw new SQLNonTransientException("SQL AST nodes type mismatch!");
                }
                canUpdate = rightExpr.toString().equals(value.toString()) && (!hasOR) && (!parentHasOR);
            }
        } else if (nodeOpExpr.getOperator().isLogical()) {
            if (nodeOpExpr.getLeft() != null) {
                if (nodeOpExpr.getLeft() instanceof SQLBinaryOpExpr) {
                    canUpdate = shardColCanBeUpdated(nodeOpExpr.getLeft(), column, value, parentHasOR);
                }
            // else
            // 此子语句不是 =,>,<等关系运算符(对应的类是SQLBinaryOpExpr)。比如between X and Y
            // 或者 NOT,或者单独的子查询,这些情况,我们不做处理
            }
            if ((!canUpdate) && nodeOpExpr.getRight() != null) {
                if (nodeOpExpr.getRight() instanceof SQLBinaryOpExpr) {
                    canUpdate = shardColCanBeUpdated(nodeOpExpr.getRight(), column, value, parentHasOR);
                }
            // else
            // 此子语句不是 =,>,<等关系运算符(对应的类是SQLBinaryOpExpr)。比如between X and Y
            // 或者 NOT,或者单独的子查询,这些情况,我们不做处理
            }
        } else if (isSubQueryClause(nodeOpExpr)) {
            // 对于子查询的检查有点复杂,这里暂时不支持
            return false;
        }
    // else
    // 其他类型的子句,忽略, 如果分片字段在这类子句中,此类情况目前不做处理,将返回false
    }
    return canUpdate;
}
Also used : SQLNonTransientException(java.sql.SQLNonTransientException) SQLExpr(com.alibaba.druid.sql.ast.SQLExpr)

Example 64 with SQLNonTransientException

use of java.sql.SQLNonTransientException in project Mycat-Server by MyCATApache.

the class DruidUpdateParser method confirmShardColumnNotUpdated.

private void confirmShardColumnNotUpdated(SQLUpdateStatement update, SchemaConfig schema, String tableName, String partitionColumn, String joinKey, RouteResultset rrs) throws SQLNonTransientException {
    List<SQLUpdateSetItem> updateSetItem = update.getItems();
    if (updateSetItem != null && updateSetItem.size() > 0) {
        boolean hasParent = (schema.getTables().get(tableName).getParentTC() != null);
        for (SQLUpdateSetItem item : updateSetItem) {
            String column = StringUtil.removeBackquote(item.getColumn().toString().toUpperCase());
            // 考虑别名,前面已经限制了update分片表的个数只能有一个,所以这里别名只能是分片表的
            if (column.contains(StringUtil.TABLE_COLUMN_SEPARATOR)) {
                column = column.substring(column.indexOf(".") + 1).trim().toUpperCase();
            }
            if (partitionColumn != null && partitionColumn.equals(column)) {
                boolean canUpdate;
                canUpdate = ((update.getWhere() != null) && shardColCanBeUpdated(update.getWhere(), partitionColumn, item.getValue(), false));
                if (!canUpdate) {
                    String msg = "Sharding column can't be updated " + tableName + "->" + partitionColumn;
                    LOGGER.warn(msg);
                    throw new SQLNonTransientException(msg);
                }
            }
            if (hasParent) {
                if (column.equals(joinKey)) {
                    String msg = "Parent relevant column can't be updated " + tableName + "->" + joinKey;
                    LOGGER.warn(msg);
                    throw new SQLNonTransientException(msg);
                }
                rrs.setCacheAble(true);
            }
        }
    }
}
Also used : SQLUpdateSetItem(com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem) SQLNonTransientException(java.sql.SQLNonTransientException)

Example 65 with SQLNonTransientException

use of java.sql.SQLNonTransientException in project Mycat-Server by MyCATApache.

the class DruidUpdateParserTest method throwExceptionParse.

public void throwExceptionParse(String sql, boolean throwException) throws NoSuchMethodException {
    MySqlStatementParser parser = new MySqlStatementParser(sql);
    List<SQLStatement> statementList = parser.parseStatementList();
    SQLStatement sqlStatement = statementList.get(0);
    MySqlUpdateStatement update = (MySqlUpdateStatement) sqlStatement;
    SchemaConfig schemaConfig = mock(SchemaConfig.class);
    Map<String, TableConfig> tables = mock(Map.class);
    TableConfig tableConfig = mock(TableConfig.class);
    String tableName = "hotnews";
    when((schemaConfig).getTables()).thenReturn(tables);
    when(tables.get(tableName)).thenReturn(tableConfig);
    when(tableConfig.getParentTC()).thenReturn(null);
    RouteResultset routeResultset = new RouteResultset(sql, 11);
    Class c = DruidUpdateParser.class;
    Method method = c.getDeclaredMethod("confirmShardColumnNotUpdated", new Class[] { SQLUpdateStatement.class, SchemaConfig.class, String.class, String.class, String.class, RouteResultset.class });
    method.setAccessible(true);
    try {
        method.invoke(c.newInstance(), update, schemaConfig, tableName, "ID", "", routeResultset);
        if (throwException) {
            System.out.println("未抛异常,解析通过则不对!");
            Assert.assertTrue(false);
        } else {
            System.out.println("未抛异常,解析通过,此情况分片字段可能在update语句中但是实际不会被更新");
            Assert.assertTrue(true);
        }
    } catch (Exception e) {
        if (throwException) {
            System.out.println(e.getCause().getClass());
            Assert.assertTrue(e.getCause() instanceof SQLNonTransientException);
            System.out.println("抛异常原因为SQLNonTransientException则正确");
        } else {
            System.out.println("抛异常,需要检查");
            Assert.assertTrue(false);
        }
    }
}
Also used : SchemaConfig(io.mycat.config.model.SchemaConfig) Method(java.lang.reflect.Method) SQLStatement(com.alibaba.druid.sql.ast.SQLStatement) SQLNonTransientException(java.sql.SQLNonTransientException) InvocationTargetException(java.lang.reflect.InvocationTargetException) MySqlUpdateStatement(com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUpdateStatement) SQLNonTransientException(java.sql.SQLNonTransientException) TableConfig(io.mycat.config.model.TableConfig) MySqlStatementParser(com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser) DruidUpdateParser(io.mycat.route.parser.druid.impl.DruidUpdateParser) RouteResultset(io.mycat.route.RouteResultset)

Aggregations

SQLNonTransientException (java.sql.SQLNonTransientException)125 TableConfig (io.mycat.config.model.TableConfig)26 SQLException (java.sql.SQLException)23 Test (org.testng.annotations.Test)19 BaseTest (util.BaseTest)19 RouteResultset (io.mycat.route.RouteResultset)17 TableConfig (com.actiontech.dble.config.model.TableConfig)15 HashMap (java.util.HashMap)14 MySqlStatementParser (com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser)13 RouteResultsetNode (io.mycat.route.RouteResultsetNode)13 HashSet (java.util.HashSet)13 SQLExpr (com.alibaba.druid.sql.ast.SQLExpr)12 ColumnRoutePair (io.mycat.sqlengine.mpp.ColumnRoutePair)12 LinkedHashSet (java.util.LinkedHashSet)12 SchemaConfig (com.actiontech.dble.config.model.SchemaConfig)11 SQLStatement (com.alibaba.druid.sql.ast.SQLStatement)11 SchemaInfo (com.actiontech.dble.server.util.SchemaUtil.SchemaInfo)10 Map (java.util.Map)10 SlotFunction (io.mycat.route.function.SlotFunction)9 SQLExprTableSource (com.alibaba.druid.sql.ast.statement.SQLExprTableSource)8