Search in sources :

Example 1 with ValuesClause

use of com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause in project druid by alibaba.

the class MySqlStatementParser method parseValueClause.

private void parseValueClause(List<ValuesClause> valueClauseList, int columnSize) {
    for (int i = 0; ; ++i) {
        if (lexer.token() != Token.LPAREN) {
            throw new ParserException("syntax error, expect ')'");
        }
        lexer.nextTokenValue();
        if (lexer.token() != Token.RPAREN) {
            List<SQLExpr> valueExprList;
            if (columnSize > 0) {
                valueExprList = new ArrayList<SQLExpr>(columnSize);
            } else {
                valueExprList = new ArrayList<SQLExpr>();
            }
            for (; ; ) {
                SQLExpr expr;
                if (lexer.token() == Token.LITERAL_INT) {
                    expr = new SQLIntegerExpr(lexer.integerValue());
                    lexer.nextTokenComma();
                } else if (lexer.token() == Token.LITERAL_CHARS) {
                    expr = new SQLCharExpr(lexer.stringVal());
                    lexer.nextTokenComma();
                } else if (lexer.token() == Token.LITERAL_NCHARS) {
                    expr = new SQLNCharExpr(lexer.stringVal());
                    lexer.nextTokenComma();
                } else {
                    expr = exprParser.expr();
                }
                if (lexer.token() == Token.COMMA) {
                    valueExprList.add(expr);
                    lexer.nextTokenValue();
                    continue;
                } else if (lexer.token() == Token.RPAREN) {
                    valueExprList.add(expr);
                    break;
                } else {
                    expr = this.exprParser.primaryRest(expr);
                    if (lexer.token() != Token.COMMA && lexer.token() != Token.RPAREN) {
                        expr = this.exprParser.exprRest(expr);
                    }
                    valueExprList.add(expr);
                    if (lexer.token() == Token.COMMA) {
                        lexer.nextToken();
                        continue;
                    } else {
                        break;
                    }
                }
            }
            SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause(valueExprList);
            valueClauseList.add(values);
        } else {
            SQLInsertStatement.ValuesClause values = new SQLInsertStatement.ValuesClause(new ArrayList<SQLExpr>(0));
            valueClauseList.add(values);
        }
        if (lexer.token() != Token.RPAREN) {
            throw new ParserException("syntax error");
        }
        if (!parseCompleteValues && valueClauseList.size() >= parseValuesSize) {
            lexer.skipToEOF();
            break;
        }
        lexer.nextTokenComma();
        if (lexer.token() == Token.COMMA) {
            lexer.nextTokenLParen();
            continue;
        } else {
            break;
        }
    }
}
Also used : ParserException(com.alibaba.druid.sql.parser.ParserException) SQLCharExpr(com.alibaba.druid.sql.ast.expr.SQLCharExpr) SQLIntegerExpr(com.alibaba.druid.sql.ast.expr.SQLIntegerExpr) ValuesClause(com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause) SQLNCharExpr(com.alibaba.druid.sql.ast.expr.SQLNCharExpr) SQLCommentHint(com.alibaba.druid.sql.ast.SQLCommentHint) SQLExpr(com.alibaba.druid.sql.ast.SQLExpr) ValuesClause(com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause)

Example 2 with ValuesClause

use of com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause in project Mycat_plus by coderczp.

the class GlobalTableUtil method convertInsertSQL.

/**
 * Syntax:
 *		INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
 *	    [INTO] tbl_name
 *	    [PARTITION (partition_name,...)]
 *	    [(col_name,...)]
 *	    {VALUES | VALUE} ({expr | DEFAULT},...),(...),...
 *	    [ ON DUPLICATE KEY UPDATE
 *	      col_name=expr
 *	        [, col_name=expr] ... ]
 *
 *		Or:
 *
 *		INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
 *	    [INTO] tbl_name
 *	    [PARTITION (partition_name,...)]
 *	    SET col_name={expr | DEFAULT}, ...
 *	    [ ON DUPLICATE KEY UPDATE
 *	      col_name=expr
 *	        [, col_name=expr] ... ]
 *
 *		Or:
 *
 *		INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
 *	    [INTO] tbl_name
 *	    [PARTITION (partition_name,...)]
 *	    [(col_name,...)]
 *	    SELECT ...
 *	    [ ON DUPLICATE KEY UPDATE
 *	      col_name=expr
 *        [, col_name=expr] ... ]
 *        mysql> insert user value (33333333,'ddd');
 *		mysql> insert into user value (333333,'ddd');
 *		mysql> insert user values (3333,'ddd');
 * insert into user(id,name) valueS(1111,'dig'),
 * (1111,  'dig'), (1111,'dig') ,(1111,'dig');
 * @param sql
 * @return
 */
private static String convertInsertSQL(String sql) {
    try {
        MySqlStatementParser parser = new MySqlStatementParser(sql);
        SQLStatement statement = parser.parseStatement();
        MySqlInsertStatement insert = (MySqlInsertStatement) statement;
        String tableName = StringUtil.removeBackquote(insert.getTableName().getSimpleName());
        if (!isGlobalTable(tableName))
            return sql;
        if (!isInnerColExist(tableName))
            return sql;
        if (// insert into tab select
        insert.getQuery() != null)
            return sql;
        StringBuilder sb = // 指定初始容量可以提高性能
        new StringBuilder(200).append("insert into ").append(tableName);
        List<SQLExpr> columns = insert.getColumns();
        int idx = -1;
        int colSize = -1;
        if (columns == null || columns.size() <= 0) {
            // insert 没有带列名:insert into t values(xxx,xxx)
            String columnsList = tableColumsMap.get(tableName.toUpperCase());
            if (StringUtils.isNotBlank(columnsList)) {
                // "id,name,_mycat_op_time"
                // newSQL = "insert into t(id,name,_mycat_op_time)";
                // 构建一个虚拟newSQL来寻找 内部列的索引位置
                String newSQL = "insert into " + tableName + "(" + columnsList + ")";
                MySqlStatementParser newParser = new MySqlStatementParser(newSQL);
                SQLStatement newStatement = newParser.parseStatement();
                MySqlInsertStatement newInsert = (MySqlInsertStatement) newStatement;
                List<SQLExpr> newColumns = newInsert.getColumns();
                for (int i = 0; i < newColumns.size(); i++) {
                    String column = StringUtil.removeBackquote(newInsert.getColumns().get(i).toString());
                    if (column.equalsIgnoreCase(GLOBAL_TABLE_MYCAT_COLUMN))
                        // 找到 内部列的索引位置
                        idx = i;
                }
                colSize = newColumns.size();
                sb.append("(").append(columnsList).append(")");
            } else {
                // tableName 是全局表,但是 tableColumsMap 没有其对应的列list,这种情况不应该存在
                LOGGER.warn("you'd better do not use 'insert into t values(a,b)' Syntax (without column list) on global table, " + "If you do. Then you must make sure inner column '_mycat_op_time' is last column of global table: " + tableName + " in all database. Good luck. ^_^");
            // 我们假定 内部列位于表中所有列的最后,后面我们在values 子句的最后 给他附加上时间戳
            }
        } else {
            // insert 语句带有 列名
            sb.append("(");
            for (int i = 0; i < columns.size(); i++) {
                if (i < columns.size() - 1)
                    sb.append(columns.get(i).toString()).append(",");
                else
                    sb.append(columns.get(i).toString());
                String column = StringUtil.removeBackquote(insert.getColumns().get(i).toString());
                if (column.equalsIgnoreCase(GLOBAL_TABLE_MYCAT_COLUMN))
                    idx = i;
            }
            if (idx <= -1)
                sb.append(",").append(GLOBAL_TABLE_MYCAT_COLUMN);
            sb.append(")");
            colSize = columns.size();
        }
        sb.append(" values");
        List<ValuesClause> vcl = insert.getValuesList();
        if (vcl != null && vcl.size() > 1) {
            // 批量insert
            for (int j = 0; j < vcl.size(); j++) {
                if (j != vcl.size() - 1)
                    appendValues(vcl.get(j).getValues(), sb, idx, colSize).append(",");
                else
                    appendValues(vcl.get(j).getValues(), sb, idx, colSize);
            }
        } else {
            // 非批量 insert
            List<SQLExpr> valuse = insert.getValues().getValues();
            appendValues(valuse, sb, idx, colSize);
        }
        List<SQLExpr> dku = insert.getDuplicateKeyUpdate();
        if (dku != null && dku.size() > 0) {
            sb.append(" on duplicate key update ");
            for (int i = 0; i < dku.size(); i++) {
                SQLExpr exp = dku.get(i);
                if (exp != null) {
                    if (i < dku.size() - 1)
                        sb.append(exp.toString()).append(",");
                    else
                        sb.append(exp.toString());
                }
            }
        }
        return sb.toString();
    } catch (Exception e) {
        // 发生异常,则返回原始 sql
        LOGGER.warn(e.getMessage());
        return sql;
    }
}
Also used : MySqlInsertStatement(com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement) MySqlStatementParser(com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser) SQLStatement(com.alibaba.druid.sql.ast.SQLStatement) SQLExpr(com.alibaba.druid.sql.ast.SQLExpr) SQLConstraint(com.alibaba.druid.sql.ast.statement.SQLConstraint) ValuesClause(com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause)

Example 3 with ValuesClause

use of com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause in project dble by actiontech.

the class DruidInsertParser method parserBatchInsert.

/**
 * insert into .... select .... or insert into table() values (),(),....
 *
 * @param schemaInfo SchemaInfo
 * @param rrs RouteResultset
 * @param partitionColumn partitionColumn
 * @param insertStmt insertStmt
 * @throws SQLNonTransientException if the column size of values is not correct
 */
private void parserBatchInsert(SchemaInfo schemaInfo, RouteResultset rrs, String partitionColumn, MySqlInsertStatement insertStmt) throws SQLNonTransientException {
    // insert into table() values (),(),....
    SchemaConfig schema = schemaInfo.getSchemaConfig();
    String tableName = schemaInfo.getTable();
    // the size of columns
    int columnNum = getTableColumns(schemaInfo, insertStmt.getColumns());
    int shardingColIndex = tryGetShardingColIndex(schemaInfo, insertStmt, partitionColumn);
    List<ValuesClause> valueClauseList = insertStmt.getValuesList();
    Map<Integer, List<ValuesClause>> nodeValuesMap = new HashMap<>();
    TableConfig tableConfig = schema.getTables().get(tableName);
    AbstractPartitionAlgorithm algorithm = tableConfig.getRule().getRuleAlgorithm();
    for (ValuesClause valueClause : valueClauseList) {
        if (valueClause.getValues().size() != columnNum) {
            String msg = "bad insert sql columnSize != valueSize:" + columnNum + " != " + valueClause.getValues().size() + "values:" + valueClause;
            LOGGER.info(msg);
            throw new SQLNonTransientException(msg);
        }
        SQLExpr expr = valueClause.getValues().get(shardingColIndex);
        String shardingValue = shardingValueToSting(expr);
        Integer nodeIndex = algorithm.calculate(shardingValue);
        // null means can't find any valid index
        if (nodeIndex == null) {
            String msg = "can't find any valid datanode :" + tableName + " -> " + partitionColumn + " -> " + shardingValue;
            LOGGER.info(msg);
            throw new SQLNonTransientException(msg);
        }
        if (nodeValuesMap.get(nodeIndex) == null) {
            nodeValuesMap.put(nodeIndex, new ArrayList<ValuesClause>());
        }
        nodeValuesMap.get(nodeIndex).add(valueClause);
    }
    RouteResultsetNode[] nodes = new RouteResultsetNode[nodeValuesMap.size()];
    int count = 0;
    for (Map.Entry<Integer, List<ValuesClause>> node : nodeValuesMap.entrySet()) {
        Integer nodeIndex = node.getKey();
        List<ValuesClause> valuesList = node.getValue();
        insertStmt.setValuesList(valuesList);
        nodes[count] = new RouteResultsetNode(tableConfig.getDataNodes().get(nodeIndex), rrs.getSqlType(), RouterUtil.removeSchema(insertStmt.toString(), schemaInfo.getSchema()));
        count++;
    }
    rrs.setNodes(nodes);
    rrs.setFinishedRoute(true);
}
Also used : AbstractPartitionAlgorithm(com.actiontech.dble.route.function.AbstractPartitionAlgorithm) SchemaConfig(com.actiontech.dble.config.model.SchemaConfig) SQLExpr(com.alibaba.druid.sql.ast.SQLExpr) SQLNonTransientException(java.sql.SQLNonTransientException) RouteResultsetNode(com.actiontech.dble.route.RouteResultsetNode) TableConfig(com.actiontech.dble.config.model.TableConfig) ValuesClause(com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause)

Example 4 with ValuesClause

use of com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause in project Mycat-Server by MyCATApache.

the class GlobalTableUtil method convertInsertSQL.

/**
 * Syntax:
 *		INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
 *	    [INTO] tbl_name
 *	    [PARTITION (partition_name,...)]
 *	    [(col_name,...)]
 *	    {VALUES | VALUE} ({expr | DEFAULT},...),(...),...
 *	    [ ON DUPLICATE KEY UPDATE
 *	      col_name=expr
 *	        [, col_name=expr] ... ]
 *
 *		Or:
 *
 *		INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
 *	    [INTO] tbl_name
 *	    [PARTITION (partition_name,...)]
 *	    SET col_name={expr | DEFAULT}, ...
 *	    [ ON DUPLICATE KEY UPDATE
 *	      col_name=expr
 *	        [, col_name=expr] ... ]
 *
 *		Or:
 *
 *		INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
 *	    [INTO] tbl_name
 *	    [PARTITION (partition_name,...)]
 *	    [(col_name,...)]
 *	    SELECT ...
 *	    [ ON DUPLICATE KEY UPDATE
 *	      col_name=expr
 *        [, col_name=expr] ... ]
 *        mysql> insert user value (33333333,'ddd');
 *		mysql> insert into user value (333333,'ddd');
 *		mysql> insert user values (3333,'ddd');
 * insert into user(id,name) valueS(1111,'dig'),
 * (1111,  'dig'), (1111,'dig') ,(1111,'dig');
 * @param sql
 * @return
 */
private static String convertInsertSQL(String sql) {
    try {
        MySqlStatementParser parser = new MySqlStatementParser(sql);
        SQLStatement statement = parser.parseStatement();
        MySqlInsertStatement insert = (MySqlInsertStatement) statement;
        String tableName = StringUtil.removeBackquote(insert.getTableName().getSimpleName());
        if (!isGlobalTable(tableName))
            return sql;
        if (!isInnerColExist(tableName))
            return sql;
        if (// insert into tab select
        insert.getQuery() != null)
            return sql;
        StringBuilder sb = // 指定初始容量可以提高性能
        new StringBuilder(200).append("insert into ").append(tableName);
        List<SQLExpr> columns = insert.getColumns();
        int idx = -1;
        int colSize = -1;
        if (columns == null || columns.size() <= 0) {
            // insert 没有带列名:insert into t values(xxx,xxx)
            String columnsList = tableColumsMap.get(tableName.toUpperCase());
            if (StringUtils.isNotBlank(columnsList)) {
                // "id,name,_mycat_op_time"
                // newSQL = "insert into t(id,name,_mycat_op_time)";
                // 构建一个虚拟newSQL来寻找 内部列的索引位置
                String newSQL = "insert into " + tableName + "(" + columnsList + ")";
                MySqlStatementParser newParser = new MySqlStatementParser(newSQL);
                SQLStatement newStatement = newParser.parseStatement();
                MySqlInsertStatement newInsert = (MySqlInsertStatement) newStatement;
                List<SQLExpr> newColumns = newInsert.getColumns();
                for (int i = 0; i < newColumns.size(); i++) {
                    String column = StringUtil.removeBackquote(newInsert.getColumns().get(i).toString());
                    if (column.equalsIgnoreCase(GLOBAL_TABLE_MYCAT_COLUMN))
                        // 找到 内部列的索引位置
                        idx = i;
                }
                colSize = newColumns.size();
                sb.append("(").append(columnsList).append(")");
            } else {
                // tableName 是全局表,但是 tableColumsMap 没有其对应的列list,这种情况不应该存在
                LOGGER.warn("you'd better do not use 'insert into t values(a,b)' Syntax (without column list) on global table, " + "If you do. Then you must make sure inner column '_mycat_op_time' is last column of global table: " + tableName + " in all database. Good luck. ^_^");
            // 我们假定 内部列位于表中所有列的最后,后面我们在values 子句的最后 给他附加上时间戳
            }
        } else {
            // insert 语句带有 列名
            sb.append("(");
            for (int i = 0; i < columns.size(); i++) {
                if (i < columns.size() - 1)
                    sb.append(columns.get(i).toString()).append(",");
                else
                    sb.append(columns.get(i).toString());
                String column = StringUtil.removeBackquote(insert.getColumns().get(i).toString());
                if (column.equalsIgnoreCase(GLOBAL_TABLE_MYCAT_COLUMN))
                    idx = i;
            }
            if (idx <= -1)
                sb.append(",").append(GLOBAL_TABLE_MYCAT_COLUMN);
            sb.append(")");
            colSize = columns.size();
        }
        sb.append(" values");
        List<ValuesClause> vcl = insert.getValuesList();
        if (vcl != null && vcl.size() > 1) {
            // 批量insert
            for (int j = 0; j < vcl.size(); j++) {
                if (j != vcl.size() - 1)
                    appendValues(vcl.get(j).getValues(), sb, idx, colSize).append(",");
                else
                    appendValues(vcl.get(j).getValues(), sb, idx, colSize);
            }
        } else {
            // 非批量 insert
            List<SQLExpr> valuse = insert.getValues().getValues();
            appendValues(valuse, sb, idx, colSize);
        }
        List<SQLExpr> dku = insert.getDuplicateKeyUpdate();
        if (dku != null && dku.size() > 0) {
            sb.append(" on duplicate key update ");
            for (int i = 0; i < dku.size(); i++) {
                SQLExpr exp = dku.get(i);
                if (exp != null) {
                    if (i < dku.size() - 1)
                        sb.append(exp.toString()).append(",");
                    else
                        sb.append(exp.toString());
                }
            }
        }
        return sb.toString();
    } catch (Exception e) {
        // 发生异常,则返回原始 sql
        LOGGER.warn(e.getMessage());
        return sql;
    }
}
Also used : MySqlInsertStatement(com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement) MySqlStatementParser(com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser) SQLStatement(com.alibaba.druid.sql.ast.SQLStatement) SQLExpr(com.alibaba.druid.sql.ast.SQLExpr) SQLConstraint(com.alibaba.druid.sql.ast.statement.SQLConstraint) ValuesClause(com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause)

Example 5 with ValuesClause

use of com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause in project druid by alibaba.

the class SQLInsertInto method cloneTo.

public void cloneTo(SQLInsertInto x) {
    if (tableSource != null) {
        x.setTableSource(tableSource.clone());
    }
    for (SQLExpr column : columns) {
        SQLExpr column2 = column.clone();
        column2.setParent(x);
        x.columns.add(column2);
    }
    if (query != null) {
        x.setQuery(query.clone());
    }
    for (ValuesClause v : valuesList) {
        ValuesClause v2 = v.clone();
        v2.setParent(x);
        x.valuesList.add(v2);
    }
    if (hint != null) {
        x.setHint(hint.clone());
    }
    x.overwrite = overwrite;
    if (partitions != null) {
        for (SQLAssignItem item : partitions) {
            x.addPartition(item.clone());
        }
    }
}
Also used : ValuesClause(com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause)

Aggregations

ValuesClause (com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause)10 SQLExpr (com.alibaba.druid.sql.ast.SQLExpr)6 SQLIntegerExpr (com.alibaba.druid.sql.ast.expr.SQLIntegerExpr)5 SQLStatement (com.alibaba.druid.sql.ast.SQLStatement)4 MySqlInsertStatement (com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement)4 MySqlStatementParser (com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser)4 TableConfig (io.mycat.config.model.TableConfig)4 SQLCharExpr (com.alibaba.druid.sql.ast.expr.SQLCharExpr)3 SQLNonTransientException (java.sql.SQLNonTransientException)3 SQLIdentifierExpr (com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr)2 SQLConstraint (com.alibaba.druid.sql.ast.statement.SQLConstraint)2 RouteResultsetNode (io.mycat.route.RouteResultsetNode)2 AbstractPartitionAlgorithm (io.mycat.route.function.AbstractPartitionAlgorithm)2 SlotFunction (io.mycat.route.function.SlotFunction)2 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 List (java.util.List)2 Map (java.util.Map)2 SchemaConfig (com.actiontech.dble.config.model.SchemaConfig)1 TableConfig (com.actiontech.dble.config.model.TableConfig)1