Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@
import com.alibaba.druid.sql.ast.statement.SQLReplaceStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMultiInsertStatement;
import org.apache.seata.common.exception.NotSupportYetException;
import org.apache.seata.common.util.CollectionUtils;
import org.apache.seata.sqlparser.SQLRecognizer;
import org.apache.seata.sqlparser.SQLRecognizerFactory;
import org.apache.seata.sqlparser.druid.oracle.OracleOperateRecognizerHolder;

import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -72,6 +74,10 @@ public List<SQLRecognizer> create(String sql, String dbType) {
recognizer = recognizerHolder.getDeleteRecognizer(sql, sqlStatement);
} else if (sqlStatement instanceof SQLSelectStatement) {
recognizer = recognizerHolder.getSelectForUpdateRecognizer(sql, sqlStatement);
} else if (sqlStatement instanceof OracleMultiInsertStatement) {
// Use specialized methods to handle Oracle bulk inserts
recognizer =
((OracleOperateRecognizerHolder) recognizerHolder).getMultiInsertRecognizer(sql, sqlStatement);
}

// When recognizer is null, it indicates that recognizerHolder cannot allocate unsupported syntax, like
Expand Down
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By default, only the insert all syntax of Oracle Batch Insert and the same column situation is supported. The same effect can be achieved by adding multiple values ​​clauses to a normal insert. Are there plans to support more in the future?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, we only support batch insert of multiple columns (same columns) in a single table. We will continue to support this in the future.

Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.seata.sqlparser.druid.oracle;

import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.alibaba.druid.sql.ast.expr.SQLNullExpr;
import com.alibaba.druid.sql.ast.expr.SQLSequenceExpr;
import com.alibaba.druid.sql.ast.expr.SQLValuableExpr;
import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLInsertStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMultiInsertStatement;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleOutputVisitor;
import org.apache.seata.common.util.CollectionUtils;
import org.apache.seata.sqlparser.SQLInsertRecognizer;
import org.apache.seata.sqlparser.SQLType;
import org.apache.seata.sqlparser.struct.NotPlaceholderExpr;
import org.apache.seata.sqlparser.struct.Null;
import org.apache.seata.sqlparser.struct.SqlMethodExpr;
import org.apache.seata.sqlparser.struct.SqlSequenceExpr;
import org.apache.seata.sqlparser.util.ColumnUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
* Oracle Multi Insert Recognizer for INSERT ALL statements
*/
public class OracleMultiInsertRecognizer extends BaseOracleRecognizer implements SQLInsertRecognizer {

private final OracleMultiInsertStatement ast;

public OracleMultiInsertRecognizer(String originalSQL, SQLStatement ast) {
super(originalSQL);
this.ast = (OracleMultiInsertStatement) ast;
}

@Override
public SQLType getSQLType() {
return SQLType.INSERT;
}

@Override
public String getTableAlias() {
// Oracle Multi Insert usually only one table is involved, take the table alias of the first inserted item
if (!CollectionUtils.isEmpty(ast.getEntries())) {
OracleMultiInsertStatement.Entry firstEntry = ast.getEntries().get(0);
if (firstEntry instanceof OracleMultiInsertStatement.InsertIntoClause) {
OracleMultiInsertStatement.InsertIntoClause insertClause =
(OracleMultiInsertStatement.InsertIntoClause) firstEntry;
if (insertClause.getTableSource() != null) {
return insertClause.getTableSource().getAlias();
}
}
}
return null;
}

@Override
public String getTableName() {
// Oracle Multi Insert usually only one table is involved, take the table alias of the first inserted item
if (!CollectionUtils.isEmpty(ast.getEntries())) {
OracleMultiInsertStatement.Entry firstEntry = ast.getEntries().get(0);
if (firstEntry instanceof OracleMultiInsertStatement.InsertIntoClause) {
OracleMultiInsertStatement.InsertIntoClause insertClause =
(OracleMultiInsertStatement.InsertIntoClause) firstEntry;
if (insertClause.getTableSource() != null) {
StringBuilder sb = new StringBuilder();
OracleOutputVisitor visitor = new OracleOutputVisitor(sb) {
@Override
public boolean visit(SQLExprTableSource x) {
printTableSourceExpr(x.getExpr());
return false;
}
};
visitor.visit(insertClause.getTableSource());
return sb.toString();
}
}
}
return null;
}

@Override
public boolean insertColumnsIsEmpty() {
if (!CollectionUtils.isEmpty(ast.getEntries())) {
OracleMultiInsertStatement.Entry firstEntry = ast.getEntries().get(0);
if (firstEntry instanceof OracleMultiInsertStatement.InsertIntoClause) {
OracleMultiInsertStatement.InsertIntoClause insertClause =
(OracleMultiInsertStatement.InsertIntoClause) firstEntry;
return CollectionUtils.isEmpty(insertClause.getColumns());
}
}
return true;
}

@Override
public List<String> getInsertColumns() {
if (!CollectionUtils.isEmpty(ast.getEntries())) {
OracleMultiInsertStatement.Entry firstEntry = ast.getEntries().get(0);
if (firstEntry instanceof OracleMultiInsertStatement.InsertIntoClause) {
OracleMultiInsertStatement.InsertIntoClause insertClause =
(OracleMultiInsertStatement.InsertIntoClause) firstEntry;
if (!CollectionUtils.isEmpty(insertClause.getColumns())) {
List<SQLExpr> columnSQLExprs = insertClause.getColumns();
List<String> list = new ArrayList<>(columnSQLExprs.size());
for (SQLExpr expr : columnSQLExprs) {
if (expr instanceof SQLIdentifierExpr) {
list.add(((SQLIdentifierExpr) expr).getName());
} else {
wrapSQLParsingException(expr);
}
}
return list;
}
}
}
return null;
}

@Override
public List<List<Object>> getInsertRows(Collection<Integer> primaryKeyIndex) {
List<List<Object>> allRows = new ArrayList<>();

if (!CollectionUtils.isEmpty(ast.getEntries())) {
for (OracleMultiInsertStatement.Entry entry : ast.getEntries()) {
if (entry instanceof OracleMultiInsertStatement.InsertIntoClause) {
OracleMultiInsertStatement.InsertIntoClause insertClause =
(OracleMultiInsertStatement.InsertIntoClause) entry;

if (!CollectionUtils.isEmpty(insertClause.getValuesList())) {
for (SQLInsertStatement.ValuesClause valuesClause : insertClause.getValuesList()) {
List<SQLExpr> exprs = valuesClause.getValues();
List<Object> row = new ArrayList<>(exprs.size());
allRows.add(row);

for (int i = 0, len = exprs.size(); i < len; i++) {
SQLExpr expr = exprs.get(i);
if (expr instanceof SQLNullExpr) {
row.add(Null.get());
} else if (expr instanceof SQLValuableExpr) {
row.add(((SQLValuableExpr) expr).getValue());
} else if (expr instanceof SQLVariantRefExpr) {
row.add(((SQLVariantRefExpr) expr).getName());
} else if (expr instanceof SQLMethodInvokeExpr) {
row.add(SqlMethodExpr.get());
} else if (expr instanceof SQLSequenceExpr) {
SQLSequenceExpr sequenceExpr = (SQLSequenceExpr) expr;
String sequence = sequenceExpr.getSequence().getSimpleName();
String function = sequenceExpr.getFunction().name;
row.add(new SqlSequenceExpr(sequence, function));
} else {
if (primaryKeyIndex.contains(i)) {
wrapSQLParsingException(expr);
}
row.add(NotPlaceholderExpr.get());
}
}
}
}
}
}
}
return allRows;
}

@Override
public List<String> getInsertParamsValue() {
return null;
}

@Override
public List<String> getDuplicateKeyUpdate() {
return null;
}

@Override
public List<String> getInsertColumnsUnEscape() {
List<String> insertColumns = getInsertColumns();
return ColumnUtils.delEscape(insertColumns, getDbType());
}

@Override
protected SQLStatement getAst() {
return ast;
}

@Override
public boolean isSqlSyntaxSupports() {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,8 @@ public SQLRecognizer getSelectForUpdateRecognizer(String sql, SQLStatement ast)
}
return null;
}

public SQLRecognizer getMultiInsertRecognizer(String sql, SQLStatement ast) {
return new OracleMultiInsertRecognizer(sql, ast);
}
}
Loading
Loading