com.oceanbase.tools.sqlparser.adapter.mysql.MySQLTableElementFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ob-sql-parser Show documentation
Show all versions of ob-sql-parser Show documentation
ob-sql-parser parses an SQL statement into a Java classes.
/*
* Copyright (c) 2023 OceanBase.
*
* Licensed 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 com.oceanbase.tools.sqlparser.adapter.mysql;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.antlr.v4.runtime.ParserRuleContext;
import com.oceanbase.tools.sqlparser.adapter.StatementFactory;
import com.oceanbase.tools.sqlparser.obmysql.OBParser.Column_attributeContext;
import com.oceanbase.tools.sqlparser.obmysql.OBParser.Column_definitionContext;
import com.oceanbase.tools.sqlparser.obmysql.OBParser.Cur_timestamp_funcContext;
import com.oceanbase.tools.sqlparser.obmysql.OBParser.Generated_column_attributeContext;
import com.oceanbase.tools.sqlparser.obmysql.OBParser.Index_using_algorithmContext;
import com.oceanbase.tools.sqlparser.obmysql.OBParser.Now_or_signed_literalContext;
import com.oceanbase.tools.sqlparser.obmysql.OBParser.Opt_column_attribute_listContext;
import com.oceanbase.tools.sqlparser.obmysql.OBParser.Opt_generated_column_attribute_listContext;
import com.oceanbase.tools.sqlparser.obmysql.OBParser.Opt_index_optionsContext;
import com.oceanbase.tools.sqlparser.obmysql.OBParser.Opt_reference_option_listContext;
import com.oceanbase.tools.sqlparser.obmysql.OBParser.Out_of_line_constraintContext;
import com.oceanbase.tools.sqlparser.obmysql.OBParser.Out_of_line_indexContext;
import com.oceanbase.tools.sqlparser.obmysql.OBParser.Out_of_line_primary_indexContext;
import com.oceanbase.tools.sqlparser.obmysql.OBParser.Out_of_line_unique_indexContext;
import com.oceanbase.tools.sqlparser.obmysql.OBParser.Reference_actionContext;
import com.oceanbase.tools.sqlparser.obmysql.OBParser.Reference_optionContext;
import com.oceanbase.tools.sqlparser.obmysql.OBParser.References_clauseContext;
import com.oceanbase.tools.sqlparser.obmysql.OBParser.Signed_literalContext;
import com.oceanbase.tools.sqlparser.obmysql.OBParser.Sort_column_listContext;
import com.oceanbase.tools.sqlparser.obmysql.OBParser.Table_elementContext;
import com.oceanbase.tools.sqlparser.obmysql.OBParserBaseVisitor;
import com.oceanbase.tools.sqlparser.statement.Expression;
import com.oceanbase.tools.sqlparser.statement.Operator;
import com.oceanbase.tools.sqlparser.statement.common.DataType;
import com.oceanbase.tools.sqlparser.statement.common.RelationFactor;
import com.oceanbase.tools.sqlparser.statement.createtable.ColumnAttributes;
import com.oceanbase.tools.sqlparser.statement.createtable.ColumnDefinition;
import com.oceanbase.tools.sqlparser.statement.createtable.ColumnDefinition.Location;
import com.oceanbase.tools.sqlparser.statement.createtable.ConstraintState;
import com.oceanbase.tools.sqlparser.statement.createtable.ForeignReference;
import com.oceanbase.tools.sqlparser.statement.createtable.ForeignReference.MatchOption;
import com.oceanbase.tools.sqlparser.statement.createtable.ForeignReference.OnOption;
import com.oceanbase.tools.sqlparser.statement.createtable.GenerateOption;
import com.oceanbase.tools.sqlparser.statement.createtable.GenerateOption.Type;
import com.oceanbase.tools.sqlparser.statement.createtable.InLineCheckConstraint;
import com.oceanbase.tools.sqlparser.statement.createtable.InLineConstraint;
import com.oceanbase.tools.sqlparser.statement.createtable.IndexOptions;
import com.oceanbase.tools.sqlparser.statement.createtable.OutOfLineCheckConstraint;
import com.oceanbase.tools.sqlparser.statement.createtable.OutOfLineConstraint;
import com.oceanbase.tools.sqlparser.statement.createtable.OutOfLineForeignConstraint;
import com.oceanbase.tools.sqlparser.statement.createtable.OutOfLineIndex;
import com.oceanbase.tools.sqlparser.statement.createtable.SortColumn;
import com.oceanbase.tools.sqlparser.statement.createtable.TableElement;
import com.oceanbase.tools.sqlparser.statement.expression.ColumnReference;
import com.oceanbase.tools.sqlparser.statement.expression.CompoundExpression;
import com.oceanbase.tools.sqlparser.statement.expression.ConstExpression;
import com.oceanbase.tools.sqlparser.statement.expression.ExpressionParam;
import com.oceanbase.tools.sqlparser.statement.expression.FunctionCall;
import com.oceanbase.tools.sqlparser.statement.expression.FunctionParam;
import lombok.NonNull;
/**
* {@link MySQLTableElementFactory}
*
* @author yh263208
* @date 2023-05-23
* @since ODC_release_4.2.0
*/
public class MySQLTableElementFactory extends OBParserBaseVisitor
implements StatementFactory {
private final ParserRuleContext parserRuleContext;
public MySQLTableElementFactory(@NonNull Table_elementContext tableElementContext) {
this.parserRuleContext = tableElementContext;
}
public MySQLTableElementFactory(@NonNull Column_definitionContext columnDefinitionContext) {
this.parserRuleContext = columnDefinitionContext;
}
public MySQLTableElementFactory(@NonNull Out_of_line_indexContext context) {
this.parserRuleContext = context;
}
public MySQLTableElementFactory(@NonNull Out_of_line_constraintContext context) {
this.parserRuleContext = context;
}
@Override
public TableElement generate() {
return visit(this.parserRuleContext);
}
@Override
public TableElement visitOut_of_line_constraint(Out_of_line_constraintContext ctx) {
OutOfLineConstraint constraint;
if (ctx.out_of_line_unique_index() != null) {
constraint = new OutOfLineConstraint(ctx, (OutOfLineConstraint) visit(ctx.out_of_line_unique_index()));
} else if (ctx.out_of_line_primary_index() != null) {
constraint = new OutOfLineConstraint(ctx, (OutOfLineConstraint) visit(ctx.out_of_line_primary_index()));
} else if (ctx.FOREIGN() != null) {
List columns = ctx.column_name_list().column_name().stream()
.map(c -> new SortColumn(c, new ColumnReference(c, null, null, c.getText())))
.collect(Collectors.toList());
constraint =
new OutOfLineForeignConstraint(ctx, null, columns, visitForeignReference(ctx.references_clause()));
constraint.setIndexName(ctx.index_name() == null ? null : ctx.index_name().getText());
} else {
ConstraintState state = null;
if (ctx.check_state() != null) {
state = new ConstraintState(ctx.check_state());
state.setEnforced(ctx.check_state().NOT() == null);
}
constraint = new OutOfLineCheckConstraint(ctx, state, new MySQLExpressionFactory(ctx.expr()).generate());
}
if (ctx.opt_constraint_name() != null && ctx.opt_constraint_name().constraint_name() != null) {
constraint.setConstraintName(ctx.opt_constraint_name().constraint_name().getText());
}
return constraint;
}
@Override
public TableElement visitOut_of_line_index(Out_of_line_indexContext ctx) {
String name = ctx.index_name() == null ? null : ctx.index_name().getText();
OutOfLineIndex index = new OutOfLineIndex(ctx, name, getSortColumns(ctx.sort_column_list()));
index.setIndexOptions(getIndexOptions(ctx.index_using_algorithm(), ctx.opt_index_options()));
index.setSpatial(ctx.SPATIAL() != null);
index.setFullText(ctx.FULLTEXT() != null);
if (ctx.partition_option() != null) {
index.setPartition(new MySQLPartitionFactory(ctx.partition_option()).generate());
} else if (ctx.auto_partition_option() != null) {
index.setPartition(new MySQLPartitionFactory(ctx.auto_partition_option()).generate());
}
return index;
}
@Override
public TableElement visitOut_of_line_primary_index(Out_of_line_primary_indexContext ctx) {
List columns = ctx.column_name_list().column_name().stream()
.map(c -> new SortColumn(c, new ColumnReference(c, null, null, c.getText())))
.collect(Collectors.toList());
IndexOptions indexOptions = getIndexOptions(ctx.index_using_algorithm(), ctx.opt_index_options());
ConstraintState state = null;
if (indexOptions != null) {
state = ctx.opt_index_options() != null
? new ConstraintState(ctx.opt_index_options())
: new ConstraintState(ctx.index_using_algorithm());
state.setIndexOptions(indexOptions);
}
OutOfLineConstraint constraint = new OutOfLineConstraint(ctx, state, columns);
constraint.setPrimaryKey(true);
constraint.setIndexName(ctx.index_name() == null ? null : ctx.index_name().getText());
return constraint;
}
@Override
public TableElement visitOut_of_line_unique_index(Out_of_line_unique_indexContext ctx) {
IndexOptions indexOptions = getIndexOptions(ctx.index_using_algorithm(), ctx.opt_index_options());
ConstraintState state = null;
if (indexOptions != null) {
state = ctx.opt_index_options() != null
? new ConstraintState(ctx.opt_index_options())
: new ConstraintState(ctx.index_using_algorithm());
state.setIndexOptions(indexOptions);
}
if (ctx.partition_option() != null) {
if (state == null) {
state = new ConstraintState(ctx.partition_option());
}
state.setPartition(new MySQLPartitionFactory(ctx.partition_option()).generate());
} else if (ctx.auto_partition_option() != null) {
if (state == null) {
state = new ConstraintState(ctx.auto_partition_option());
}
state.setPartition(new MySQLPartitionFactory(ctx.auto_partition_option()).generate());
}
OutOfLineConstraint constraint = new OutOfLineConstraint(ctx, state, getSortColumns(ctx.sort_column_list()));
constraint.setUniqueKey(true);
constraint.setIndexName(ctx.index_name() == null ? null : ctx.index_name().getText());
return constraint;
}
@Override
public TableElement visitColumn_definition(Column_definitionContext ctx) {
DataType dataType = null;
if (ctx.data_type() != null) {
dataType = new MySQLDataTypeFactory(ctx.data_type()).generate();
}
StatementFactory factory = new MySQLColumnRefFactory(ctx.column_definition_ref());
ColumnDefinition definition = new ColumnDefinition(ctx, factory.generate(), dataType);
if (ctx.AS() != null) {
// generated column
StatementFactory exprFactory = new MySQLExpressionFactory(ctx.expr());
GenerateOption generateOption = new GenerateOption(ctx, exprFactory.generate());
if (ctx.opt_generated_option_list() != null) {
generateOption.setGenerateOption(ctx.opt_generated_option_list().getText());
}
if (ctx.VIRTUAL() != null) {
generateOption.setType(Type.VIRTUAL);
} else if (ctx.STORED() != null) {
generateOption.setType(Type.STORED);
}
definition.setGenerateOption(generateOption);
}
if (ctx.opt_column_attribute_list() != null) {
ColumnAttributes attributes = visitColumnAttributeList(ctx.opt_column_attribute_list());
definition.setColumnAttributes(attributes);
} else if (ctx.opt_generated_column_attribute_list() != null) {
ColumnAttributes attributes = visitGeneratedColumnAttributeList(ctx.opt_generated_column_attribute_list());
definition.setColumnAttributes(attributes);
}
if (ctx.FIRST() != null) {
definition.setLocation(new Location(ctx.FIRST().getText(), null));
} else if (ctx.BEFORE() != null) {
ColumnReference r = new ColumnReference(ctx.column_name(), null, null, ctx.column_name().getText());
definition.setLocation(new Location(ctx.BEFORE().getText(), r));
} else if (ctx.AFTER() != null) {
ColumnReference r = new ColumnReference(ctx.column_name(), null, null, ctx.column_name().getText());
definition.setLocation(new Location(ctx.AFTER().getText(), r));
}
return definition;
}
private ForeignReference visitForeignReference(References_clauseContext context) {
RelationFactor factor = MySQLFromReferenceFactory.getRelationFactor(context.relation_factor());
List columns = new ArrayList<>();
if (context.column_name_list() != null) {
columns = context.column_name_list().column_name().stream()
.map(c1 -> new ColumnReference(c1, null, null, c1.getText()))
.collect(Collectors.toList());
}
ForeignReference foreignReference = new ForeignReference(context,
factor.getSchema(), factor.getRelation(), columns);
foreignReference.setUserVariable(factor.getUserVariable());
if (context.match_action() != null) {
foreignReference.setMatchOption(MatchOption.valueOf(context.match_action().getText().toUpperCase()));
}
if (context.opt_reference_option_list() != null) {
Map attributes = visitReferenceOptions(context.opt_reference_option_list());
attributes.putAll(visitReferenceOption(context.reference_option()));
foreignReference.setDeleteOption(attributes.get("DELETE"));
foreignReference.setUpdateOption(attributes.get("UPDATE"));
}
return foreignReference;
}
private Map visitReferenceOptions(Opt_reference_option_listContext context) {
Map attributes = new HashMap<>();
if (context.opt_reference_option_list() != null) {
attributes.putAll(visitReferenceOptions(context.opt_reference_option_list()));
}
if (context.reference_option() == null) {
return attributes;
}
attributes.putAll(visitReferenceOption(context.reference_option()));
return attributes;
}
private Map visitReferenceOption(Reference_optionContext context) {
String key;
Map attributes = new HashMap<>();
if (context.DELETE() != null) {
key = "DELETE";
} else {
key = "UPDATE";
}
Reference_actionContext ctx = context.reference_action();
if (ctx.RESTRICT() != null) {
attributes.put(key, OnOption.RESTRICT);
} else if (ctx.CASCADE() != null) {
attributes.put(key, OnOption.CASCADE);
} else if (ctx.NULLX() != null) {
attributes.put(key, OnOption.SET_NULL);
} else if (ctx.ACTION() != null) {
attributes.put(key, OnOption.NO_ACTION);
} else {
attributes.put(key, OnOption.SET_DEFAULT);
}
return attributes;
}
private IndexOptions getIndexOptions(Index_using_algorithmContext c1,
Opt_index_optionsContext c2) {
if (c1 == null && c2 == null) {
return null;
} else if (c2 != null && c1 == null) {
return new MySQLIndexOptionsFactory(c2).generate();
} else if (c2 == null) {
IndexOptions indexOptions = new IndexOptions(c1);
indexOptions.setUsingBtree(isUsingBTree(c1));
indexOptions.setUsingHash(isUsingHash(c1));
return indexOptions;
}
IndexOptions first = getIndexOptions(c1, null);
IndexOptions second = getIndexOptions(null, c2);
if (second.getUsingHash() == null) {
second.setUsingHash(first.getUsingHash());
}
if (second.getUsingBtree() == null) {
second.setUsingBtree(first.getUsingBtree());
}
return second;
}
private ColumnAttributes visitGeneratedColumnAttributeList(Opt_generated_column_attribute_listContext cxt) {
ColumnAttributes attributes = new ColumnAttributes(cxt);
if (cxt.opt_generated_column_attribute_list() != null) {
attributes.merge(visitGeneratedColumnAttributeList(cxt.opt_generated_column_attribute_list()));
}
attributes.merge(visitGeneratedColumnAttribute(cxt.generated_column_attribute()));
return attributes;
}
private ColumnAttributes visitGeneratedColumnAttribute(Generated_column_attributeContext ctx) {
ColumnAttributes attributes = new ColumnAttributes(ctx);
if (ctx.ID() != null) {
attributes.setId(Integer.valueOf(ctx.INTNUM().getText()));
} else if (ctx.COMMENT() != null) {
attributes.setComment(ctx.STRING_VALUE().getText());
} else if (ctx.SRID() != null) {
attributes.setSrid(Integer.valueOf(ctx.INTNUM().getText()));
} else {
InLineConstraint attribute = new InLineConstraint(ctx, null, null);
if (ctx.NULLX() != null) {
attribute.setNullable(ctx.NOT() == null);
attributes.setConstraints(Collections.singletonList(attribute));
} else if (ctx.PRIMARY() != null) {
attribute.setPrimaryKey(true);
attributes.setConstraints(Collections.singletonList(attribute));
} else if (ctx.UNIQUE() != null) {
attribute.setUniqueKey(true);
attributes.setConstraints(Collections.singletonList(attribute));
} else if (ctx.KEY() != null) {
attribute.setPrimaryKey(true);
attributes.setConstraints(Collections.singletonList(attribute));
} else if (ctx.CHECK() != null) {
Expression expr = new MySQLExpressionFactory(ctx.expr()).generate();
ConstraintState state = null;
if (ctx.check_state() != null) {
state = new ConstraintState(ctx.check_state());
state.setEnforced(ctx.check_state().NOT() == null);
}
String constraintName = null;
if (ctx.opt_constraint_name() != null && ctx.opt_constraint_name().constraint_name() != null) {
constraintName = ctx.opt_constraint_name().constraint_name().getText();
}
attributes.setConstraints(
Collections.singletonList(new InLineCheckConstraint(ctx, constraintName, state, expr)));
}
}
return attributes;
}
private ColumnAttributes visitColumnAttributeList(Opt_column_attribute_listContext context) {
ColumnAttributes attributes = new ColumnAttributes(context);
if (context.opt_column_attribute_list() != null) {
attributes.merge(visitColumnAttributeList(context.opt_column_attribute_list()));
}
attributes.merge(visitColumnAttribute(context.column_attribute()));
return attributes;
}
private ColumnAttributes visitColumnAttribute(Column_attributeContext ctx) {
ColumnAttributes attributes = new ColumnAttributes(ctx);
InLineConstraint attribute = new InLineConstraint(ctx, null, null);
if (ctx.NULLX() != null) {
attribute.setNullable(ctx.not() == null);
attributes.setConstraints(Collections.singletonList(attribute));
} else if (ctx.PRIMARY() != null) {
attribute.setPrimaryKey(true);
attributes.setConstraints(Collections.singletonList(attribute));
} else if (ctx.UNIQUE() != null) {
attribute.setUniqueKey(true);
attributes.setConstraints(Collections.singletonList(attribute));
} else if (ctx.KEY() != null) {
attribute.setPrimaryKey(true);
attributes.setConstraints(Collections.singletonList(attribute));
} else if (ctx.CHECK() != null) {
ConstraintState state = null;
if (ctx.check_state() != null) {
state = new ConstraintState(ctx.check_state());
state.setEnforced(ctx.check_state().NOT() == null);
}
String constraintName = null;
if (ctx.opt_constraint_name() != null && ctx.opt_constraint_name().constraint_name() != null) {
constraintName = ctx.opt_constraint_name().constraint_name().getText();
}
attribute = new InLineCheckConstraint(ctx, constraintName, state,
new MySQLExpressionFactory(ctx.expr()).generate());
attributes.setConstraints(Collections.singletonList(attribute));
} else if (ctx.DEFAULT() != null || ctx.ORIG_DEFAULT() != null) {
Expression expr = visitNowOrSignedLiteral(ctx.now_or_signed_literal());
if (ctx.DEFAULT() != null) {
attributes.setDefaultValue(expr);
} else {
attributes.setOrigDefault(expr);
}
} else if (ctx.AUTO_INCREMENT() != null) {
attributes.setAutoIncrement(true);
} else if (ctx.COMMENT() != null) {
attributes.setComment(ctx.STRING_VALUE().getText());
} else if (ctx.ON() != null && ctx.UPDATE() != null) {
attributes.setOnUpdate(visitCurTimestampFunc(ctx.cur_timestamp_func()));
} else if (ctx.ID() != null) {
attributes.setId(Integer.valueOf(ctx.INTNUM().getText()));
} else if (ctx.SRID() != null) {
attributes.setSrid(Integer.valueOf(ctx.INTNUM().getText()));
} else if (ctx.collation_name() != null) {
attributes.setCollation(ctx.collation_name().getText());
}
return attributes;
}
private Expression visitNowOrSignedLiteral(Now_or_signed_literalContext context) {
if (context.cur_timestamp_func() != null) {
return visitCurTimestampFunc(context.cur_timestamp_func());
}
return getSignedLiteral(context.signed_literal());
}
public static Expression getSignedLiteral(Signed_literalContext context) {
if (context == null) {
return null;
}
Expression constExpr;
if (context.literal() != null) {
constExpr = new MySQLExpressionFactory(context.literal()).generate();
} else {
constExpr = new ConstExpression(context.number_literal());
}
Operator operator = null;
if (context.Minus() != null) {
operator = Operator.SUB;
} else if (context.Plus() != null) {
operator = Operator.ADD;
}
return operator == null ? constExpr : new CompoundExpression(context, constExpr, null, operator);
}
private Expression visitCurTimestampFunc(Cur_timestamp_funcContext context) {
String funcName = context.getChild(0).getText();
List params = new ArrayList<>();
if (context.INTNUM() != null) {
params.add(new ExpressionParam(new ConstExpression(context.INTNUM())));
}
return new FunctionCall(context, funcName, params);
}
public static Boolean isUsingBTree(Index_using_algorithmContext ctx) {
if (ctx == null) {
return null;
} else if (ctx.BTREE() == null) {
return null;
}
return true;
}
public static Boolean isUsingHash(Index_using_algorithmContext ctx) {
if (ctx == null) {
return null;
} else if (ctx.HASH() == null) {
return null;
}
return true;
}
private List getSortColumns(@NonNull Sort_column_listContext ctx) {
return ctx.sort_column_key().stream().map(c -> new MySQLSortColumnFactory(c).generate())
.collect(Collectors.toList());
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy