diff --git a/src/main/java/net/sf/jsqlparser/util/validation/DatabaseType.java b/src/main/java/net/sf/jsqlparser/util/validation/DatabaseType.java
new file mode 100644
index 000000000..3083b77eb
--- /dev/null
+++ b/src/main/java/net/sf/jsqlparser/util/validation/DatabaseType.java
@@ -0,0 +1,23 @@
+package net.sf.jsqlparser.util.validation;
+
+/**
+ *
+ * The DatabaseType is named like the identifier used within the
+ * jdbc-connection-url, this may change in future, therefore use
+ * {@link #get(String)} to retrieve the {@link DatabaseType}.
+ *
+ */
+public enum DatabaseType {
+
+ oracle, mysql, sqlserver;
+
+ /**
+ * @param jdbcIdentifier - the database-identifier-part of jdbc-url
+ * @return the {@link DatabaseType}
+ * @throws IllegalArgumentException - if the specified jdbcIdentifier cannot be mapped to a {@link DatabaseType}
+ */
+ public static DatabaseType get(String jdbcIdentifier) {
+ return DatabaseType.valueOf(jdbcIdentifier);
+ }
+
+}
diff --git a/src/main/java/net/sf/jsqlparser/util/validation/ExpressionValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/ExpressionValidator.java
new file mode 100644
index 000000000..4b5278544
--- /dev/null
+++ b/src/main/java/net/sf/jsqlparser/util/validation/ExpressionValidator.java
@@ -0,0 +1,661 @@
+/*-
+ * #%L
+ * JSQLParser library
+ * %%
+ * Copyright (C) 2004 - 2019 JSQLParser
+ * %%
+ * Dual licensed under GNU LGPL 2.1 or Apache License 2.0
+ * #L%
+ */
+package net.sf.jsqlparser.util.validation;
+
+import java.util.EnumMap;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import net.sf.jsqlparser.expression.*;
+import net.sf.jsqlparser.expression.operators.arithmetic.Addition;
+import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseAnd;
+import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseLeftShift;
+import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseOr;
+import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseRightShift;
+import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseXor;
+import net.sf.jsqlparser.expression.operators.arithmetic.Concat;
+import net.sf.jsqlparser.expression.operators.arithmetic.Division;
+import net.sf.jsqlparser.expression.operators.arithmetic.IntegerDivision;
+import net.sf.jsqlparser.expression.operators.arithmetic.Modulo;
+import net.sf.jsqlparser.expression.operators.arithmetic.Multiplication;
+import net.sf.jsqlparser.expression.operators.arithmetic.Subtraction;
+import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
+import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
+import net.sf.jsqlparser.expression.operators.relational.*;
+import net.sf.jsqlparser.schema.Column;
+import net.sf.jsqlparser.schema.Table;
+import net.sf.jsqlparser.statement.select.OrderByElement;
+import net.sf.jsqlparser.statement.select.SelectVisitor;
+import net.sf.jsqlparser.statement.select.SubSelect;
+import net.sf.jsqlparser.statement.select.WithItem;
+
+public class ExpressionValidator implements ExpressionVisitor, ItemsListVisitor, Validation {
+
+ protected Map> errors = new EnumMap<>(DatabaseType.class);
+ private SelectVisitor selectVisitor;
+ private boolean useBracketsInExprList = true;
+ private OrderByValidator orderByDeParser = new OrderByValidator();
+
+ public ExpressionValidator() {
+ this(null, new EnumMap<>(DatabaseType.class));
+ }
+
+ public ExpressionValidator(SelectVisitor selectVisitor, Map> errors) {
+ this(selectVisitor, errors, new OrderByValidator());
+ }
+
+ ExpressionValidator(SelectVisitor selectVisitor, Map> errors,
+ OrderByValidator orderByDeValidator) {
+ this.selectVisitor = selectVisitor;
+ this.errors = errors;
+ this.orderByDeParser = orderByDeValidator;
+ }
+
+ @Override
+ public void visit(Addition addition) {
+ visitBinaryExpression(addition, " + ");
+ }
+
+ @Override
+ public void visit(AndExpression andExpression) {
+ visitBinaryExpression(andExpression, andExpression.isUseOperator()?" && ":" AND ");
+ }
+
+ @Override
+ public void visit(Between between) {
+ between.getLeftExpression().accept(this);
+ between.getBetweenExpressionStart().accept(this);
+ between.getBetweenExpressionEnd().accept(this);
+ }
+
+ @Override
+ public void visit(EqualsTo equalsTo) {
+ visitOldOracleJoinBinaryExpression(equalsTo, " = ");
+ }
+
+ @Override
+ public void visit(Division division) {
+ visitBinaryExpression(division, " / ");
+ }
+
+ @Override
+ public void visit(IntegerDivision division) {
+ visitBinaryExpression(division, " DIV ");
+ }
+
+ @Override
+ public void visit(DoubleValue doubleValue) {
+ }
+
+ @Override
+ public void visit(HexValue hexValue) {
+ }
+
+ @Override
+ public void visit(NotExpression notExpr) {
+ notExpr.getExpression().accept(this);
+ }
+
+ @Override
+ public void visit(BitwiseRightShift expr) {
+ visitBinaryExpression(expr, " >> ");
+ }
+
+ @Override
+ public void visit(BitwiseLeftShift expr) {
+ visitBinaryExpression(expr, " << ");
+ }
+
+ public void visitOldOracleJoinBinaryExpression(OldOracleJoinBinaryExpression expression, String operator) {
+ expression.getLeftExpression().accept(this);
+ if (expression.getOldOracleJoinSyntax() != SupportsOldOracleJoinSyntax.NO_ORACLE_JOIN) {
+ Validation.mapAllExcept(errors, EnumSet.of(DatabaseType.oracle),
+ String.format("oldOracleJoinSyntax=%d not supported", expression.getOldOracleJoinSyntax()));
+ }
+ expression.getRightExpression().accept(this);
+ if (expression.getOraclePriorPosition() != SupportsOldOracleJoinSyntax.NO_ORACLE_PRIOR) {
+ Validation.mapAllExcept(errors, EnumSet.of(DatabaseType.oracle),
+ String.format("oraclePriorPosition=%d not supported", expression.getOraclePriorPosition()));
+ }
+ }
+
+ @Override
+ public void visit(GreaterThan greaterThan) {
+ visitOldOracleJoinBinaryExpression(greaterThan, " > ");
+ }
+
+ @Override
+ public void visit(GreaterThanEquals greaterThanEquals) {
+ visitOldOracleJoinBinaryExpression(greaterThanEquals, " >= ");
+
+ }
+
+ @Override
+ public void visit(InExpression inExpression) {
+ if (inExpression.getLeftExpression() == null) {
+ inExpression.getLeftItemsList().accept(this);
+ } else {
+ inExpression.getLeftExpression().accept(this);
+ if (inExpression.getOldOracleJoinSyntax() == SupportsOldOracleJoinSyntax.ORACLE_JOIN_RIGHT) {
+ }
+ }
+ if (inExpression.isNot()) {
+ }
+
+ if (inExpression.getMultiExpressionList() != null) {
+ parseMultiExpressionList(inExpression);
+ } else {
+ if (inExpression.getRightExpression() != null) {
+ inExpression.getRightExpression().accept(this);
+ } else {
+ inExpression.getRightItemsList().accept(this);
+ }
+ }
+ }
+
+ /**
+ * Produces a multi-expression in clause: {@code ((a, b), (c, d))}
+ */
+ private void parseMultiExpressionList(InExpression inExpression) {
+ MultiExpressionList multiExprList = inExpression.getMultiExpressionList();
+ for (Iterator it = multiExprList.getExprList().iterator(); it.hasNext();) {
+ for (Iterator iter = it.next().getExpressions().iterator(); iter.hasNext();) {
+ Expression expression = iter.next();
+ expression.accept(this);
+ if (iter.hasNext()) {
+ }
+ }
+ if (it.hasNext()) {
+ }
+ }
+ }
+
+ @Override
+ public void visit(FullTextSearch fullTextSearch) {
+ }
+
+ @Override
+ public void visit(SignedExpression signedExpression) {
+ signedExpression.getExpression().accept(this);
+ }
+
+ @Override
+ public void visit(IsNullExpression isNullExpression) {
+ isNullExpression.getLeftExpression().accept(this);
+ }
+
+ @Override
+ public void visit(IsBooleanExpression isBooleanExpression) {
+ isBooleanExpression.getLeftExpression().accept(this);
+ }
+
+ @Override
+ public void visit(JdbcParameter jdbcParameter) {
+ }
+
+ @Override
+ public void visit(LikeExpression likeExpression) {
+ visitBinaryExpression(likeExpression,
+ (likeExpression.isNot() ? " NOT" : "")
+ + (likeExpression.isCaseInsensitive() ? " ILIKE " : " LIKE "));
+ }
+
+ @Override
+ public void visit(ExistsExpression existsExpression) {
+ if (existsExpression.isNot()) {
+ } else {
+ }
+ existsExpression.getRightExpression().accept(this);
+ }
+
+ @Override
+ public void visit(LongValue longValue) {
+
+ }
+
+ @Override
+ public void visit(MinorThan minorThan) {
+ visitOldOracleJoinBinaryExpression(minorThan, " < ");
+
+ }
+
+ @Override
+ public void visit(MinorThanEquals minorThanEquals) {
+ visitOldOracleJoinBinaryExpression(minorThanEquals, " <= ");
+
+ }
+
+ @Override
+ public void visit(Multiplication multiplication) {
+ visitBinaryExpression(multiplication, " * ");
+
+ }
+
+ @Override
+ public void visit(NotEqualsTo notEqualsTo) {
+ visitOldOracleJoinBinaryExpression(notEqualsTo, " " + notEqualsTo.getStringExpression() + " ");
+
+ }
+
+ @Override
+ public void visit(NullValue nullValue) {
+
+ }
+
+ @Override
+ public void visit(OrExpression orExpression) {
+ visitBinaryExpression(orExpression, " OR ");
+
+ }
+
+ @Override
+ public void visit(Parenthesis parenthesis) {
+ parenthesis.getExpression().accept(this);
+ }
+
+ @Override
+ public void visit(StringValue stringValue) {
+ if (stringValue.getPrefix() != null) {
+ }
+
+ }
+
+ @Override
+ public void visit(Subtraction subtraction) {
+ visitBinaryExpression(subtraction, " - ");
+ }
+
+ protected void visitBinaryExpression(BinaryExpression binaryExpression, String operator) {
+ binaryExpression.getLeftExpression().accept(this);
+ binaryExpression.getRightExpression().accept(this);
+
+ }
+
+ @Override
+ public void visit(SubSelect subSelect) {
+ if (subSelect.isUseBrackets()) {
+ }
+ if (selectVisitor != null) {
+ if (subSelect.getWithItemsList() != null) {
+ for (Iterator iter = subSelect.getWithItemsList().iterator(); iter.
+ hasNext();) {
+ iter.next().accept(selectVisitor);
+ if (iter.hasNext()) {
+ }
+ }
+ }
+
+ subSelect.getSelectBody().accept(selectVisitor);
+ }
+ if (subSelect.isUseBrackets()) {
+ }
+ }
+
+ @Override
+ public void visit(Column tableColumn) {
+ final Table table = tableColumn.getTable();
+ String tableName = null;
+ if (table != null) {
+ if (table.getAlias() != null) {
+ tableName = table.getAlias().getName();
+ } else {
+ tableName = table.getFullyQualifiedName();
+ }
+ }
+ if (tableName != null && !tableName.isEmpty()) {
+ }
+
+ }
+
+ @Override
+ public void visit(Function function) {
+ if (function.isEscaped()) {
+ }
+
+ if (function.isAllColumns() && function.getParameters() == null) {
+ } else if (function.getParameters() == null && function.getNamedParameters() == null) {
+ } else {
+ boolean oldUseBracketsInExprList = useBracketsInExprList;
+ useBracketsInExprList = true;
+ if (function.isDistinct()) {
+ useBracketsInExprList = false;
+ } else if (function.isAllColumns()) {
+ useBracketsInExprList = false;
+ }
+ if (function.getNamedParameters() != null) {
+ visit(function.getNamedParameters());
+ }
+ if (function.getParameters() != null) {
+ visit(function.getParameters());
+ }
+ useBracketsInExprList = oldUseBracketsInExprList;
+ if (function.isDistinct() || function.isAllColumns()) {
+ }
+ }
+
+ if (function.getAttribute() != null) {
+ } else if (function.getAttributeName() != null) {
+ }
+ if (function.getKeep() != null) {
+ }
+ if (function.isEscaped()) {
+ }
+ }
+
+ @Override
+ public void visit(ExpressionList expressionList) {
+ if (useBracketsInExprList) {
+ }
+ for (Iterator iter = expressionList.getExpressions().iterator(); iter.hasNext();) {
+ Expression expression = iter.next();
+ expression.accept(this);
+ if (iter.hasNext()) {
+ }
+ }
+ if (useBracketsInExprList) {
+ }
+ }
+
+ @Override
+ public void visit(NamedExpressionList namedExpressionList) {
+ if (useBracketsInExprList) {
+ }
+ List names = namedExpressionList.getNames();
+ List expressions = namedExpressionList.getExpressions();
+ for (int i = 0; i < names.size(); i++) {
+ if (i > 0) {
+ }
+ String name = names.get(i);
+ if (!name.equals("")) {
+ }
+ expressions.get(i).accept(this);
+ }
+ if (useBracketsInExprList) {
+ }
+ }
+
+ public SelectVisitor getSelectVisitor() {
+ return selectVisitor;
+ }
+
+ public void setSelectVisitor(SelectVisitor visitor) {
+ selectVisitor = visitor;
+ }
+
+ @Override
+ public void visit(DateValue dateValue) {
+ }
+
+ @Override
+ public void visit(TimestampValue timestampValue) {
+ }
+
+ @Override
+ public void visit(TimeValue timeValue) {
+ }
+
+ @Override
+ public void visit(CaseExpression caseExpression) {
+ Expression switchExp = caseExpression.getSwitchExpression();
+ if (switchExp != null) {
+ switchExp.accept(this);
+ }
+
+ for (Expression exp : caseExpression.getWhenClauses()) {
+ exp.accept(this);
+ }
+
+ Expression elseExp = caseExpression.getElseExpression();
+ if (elseExp != null) {
+ elseExp.accept(this);
+ }
+
+ }
+
+ @Override
+ public void visit(WhenClause whenClause) {
+ whenClause.getWhenExpression().accept(this);
+ whenClause.getThenExpression().accept(this);
+ }
+
+ @Override
+ public void visit(AllComparisonExpression allComparisonExpression) {
+ allComparisonExpression.getSubSelect().accept((ExpressionVisitor) this);
+ }
+
+ @Override
+ public void visit(AnyComparisonExpression anyComparisonExpression) {
+ anyComparisonExpression.getSubSelect().accept((ExpressionVisitor) this);
+ }
+
+ @Override
+ public void visit(Concat concat) {
+ visitBinaryExpression(concat, " || ");
+ }
+
+ @Override
+ public void visit(Matches matches) {
+ visitOldOracleJoinBinaryExpression(matches, " @@ ");
+ }
+
+ @Override
+ public void visit(BitwiseAnd bitwiseAnd) {
+ visitBinaryExpression(bitwiseAnd, " & ");
+ }
+
+ @Override
+ public void visit(BitwiseOr bitwiseOr) {
+ visitBinaryExpression(bitwiseOr, " | ");
+ }
+
+ @Override
+ public void visit(BitwiseXor bitwiseXor) {
+ visitBinaryExpression(bitwiseXor, " ^ ");
+ }
+
+ @Override
+ public void visit(CastExpression cast) {
+ if (cast.isUseCastKeyword()) {
+ cast.getLeftExpression().accept(this);
+ } else {
+ cast.getLeftExpression().accept(this);
+ }
+ }
+
+ @Override
+ public void visit(Modulo modulo) {
+ visitBinaryExpression(modulo, " % ");
+ }
+
+ @Override
+ public void visit(AnalyticExpression aexpr) {
+ String name = aexpr.getName();
+ Expression expression = aexpr.getExpression();
+ Expression offset = aexpr.getOffset();
+ Expression defaultValue = aexpr.getDefaultValue();
+ boolean isAllColumns = aexpr.isAllColumns();
+ KeepExpression keep = aexpr.getKeep();
+ ExpressionList partitionExpressionList = aexpr.getPartitionExpressionList();
+ List orderByElements = aexpr.getOrderByElements();
+ WindowElement windowElement = aexpr.getWindowElement();
+
+ if (aexpr.isDistinct()) {
+ }
+ if (expression != null) {
+ expression.accept(this);
+ if (offset != null) {
+ offset.accept(this);
+ if (defaultValue != null) {
+ defaultValue.accept(this);
+ }
+ }
+ } else if (isAllColumns) {
+ }
+ if (aexpr.isIgnoreNulls()) {
+ }
+ if (keep != null) {
+ keep.accept(this);
+ }
+
+ if (aexpr.getFilterExpression() != null) {
+ aexpr.getFilterExpression().accept(this);
+ }
+
+ switch (aexpr.getType()) {
+ case WITHIN_GROUP:
+ break;
+ default:
+ }
+
+ if (partitionExpressionList != null && !partitionExpressionList.getExpressions().isEmpty()) {
+ if (aexpr.isPartitionByBrackets()) {
+ }
+ List expressions = partitionExpressionList.getExpressions();
+ for (int i = 0; i < expressions.size(); i++) {
+ if (i > 0) {
+ }
+ expressions.get(i).accept(this);
+ }
+ if (aexpr.isPartitionByBrackets()) {
+ }
+ }
+ if (orderByElements != null && !orderByElements.isEmpty()) {
+ // orderByDeValidator.setExpressionVisitor(this);
+ // orderByDeValidator.setBuffer(errors);
+ for (int i = 0; i < orderByElements.size(); i++) {
+ if (i > 0) {
+ }
+ // orderByDeParser.deParseElement(orderByElements.get(i));
+ }
+ }
+
+ if (windowElement != null) {
+ if (orderByElements != null && !orderByElements.isEmpty()) {
+ }
+ }
+
+ }
+
+ @Override
+ public void visit(ExtractExpression eexpr) {
+ eexpr.getExpression().accept(this);
+ }
+
+ @Override
+ public void visit(MultiExpressionList multiExprList) {
+ for (Iterator it = multiExprList.getExprList().iterator(); it.hasNext();) {
+ it.next().accept(this);
+ if (it.hasNext()) {
+ }
+ }
+ }
+
+ @Override
+ public void visit(IntervalExpression iexpr) {
+ }
+
+ @Override
+ public void visit(JdbcNamedParameter jdbcNamedParameter) {
+ }
+
+ @Override
+ public void visit(OracleHierarchicalExpression oexpr) {
+ }
+
+ @Override
+ public void visit(RegExpMatchOperator rexpr) {
+ visitBinaryExpression(rexpr, " " + rexpr.getStringExpression() + " ");
+ }
+
+ @Override
+ public void visit(RegExpMySQLOperator rexpr) {
+ visitBinaryExpression(rexpr, " " + rexpr.getStringExpression() + " ");
+ }
+
+ @Override
+ public void visit(JsonExpression jsonExpr) {
+ }
+
+ @Override
+ public void visit(JsonOperator jsonExpr) {
+ visitBinaryExpression(jsonExpr, " " + jsonExpr.getStringExpression() + " ");
+ }
+
+ @Override
+ public void visit(UserVariable var) {
+ }
+
+ @Override
+ public void visit(NumericBind bind) {
+ }
+
+ @Override
+ public void visit(KeepExpression aexpr) {
+ }
+
+ @Override
+ public void visit(MySQLGroupConcat groupConcat) {
+ }
+
+ @Override
+ public void visit(ValueListExpression valueList) {
+ }
+
+ @Override
+ public void visit(RowConstructor rowConstructor) {
+ if (rowConstructor.getName() != null) {
+ }
+ boolean first = true;
+ for (Expression expr : rowConstructor.getExprList().getExpressions()) {
+ if (first) {
+ first = false;
+ } else {
+ }
+ expr.accept(this);
+ }
+ }
+
+ @Override
+ public void visit(OracleHint hint) {
+ }
+
+ @Override
+ public void visit(TimeKeyExpression timeKeyExpression) {
+ }
+ @Override
+ public void visit(DateTimeLiteralExpression literal) {
+ }
+
+ @Override
+ public void visit(NextValExpression nextVal) {
+ }
+
+ @Override
+ public void visit(CollateExpression col) {
+ }
+
+ @Override
+ public void visit(SimilarToExpression expr) {
+ visitBinaryExpression(expr, (expr.isNot() ? " NOT" : "") + " SIMILAR TO ");
+ }
+
+ @Override
+ public void visit(ArrayExpression array) {
+ array.getObjExpression().accept(this);
+ array.getIndexExpression().accept(this);
+ }
+
+ @Override
+ public Map> getValidationErrors() {
+ return errors;
+ }
+}
diff --git a/src/main/java/net/sf/jsqlparser/util/validation/OrderByValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/OrderByValidator.java
new file mode 100644
index 000000000..14bb1b9f5
--- /dev/null
+++ b/src/main/java/net/sf/jsqlparser/util/validation/OrderByValidator.java
@@ -0,0 +1,5 @@
+package net.sf.jsqlparser.util.validation;
+
+public class OrderByValidator {
+
+}
diff --git a/src/main/java/net/sf/jsqlparser/util/validation/SelectValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/SelectValidator.java
new file mode 100644
index 000000000..ce021b931
--- /dev/null
+++ b/src/main/java/net/sf/jsqlparser/util/validation/SelectValidator.java
@@ -0,0 +1,503 @@
+/*-
+ * #%L
+ * JSQLParser library
+ * %%
+ * Copyright (C) 2004 - 2019 JSQLParser
+ * %%
+ * Dual licensed under GNU LGPL 2.1 or Apache License 2.0
+ * #L%
+ */
+package net.sf.jsqlparser.util.validation;
+
+import java.util.EnumMap;
+import java.util.Map;
+import java.util.Set;
+import net.sf.jsqlparser.schema.Table;
+import net.sf.jsqlparser.statement.select.*;
+import net.sf.jsqlparser.statement.values.ValuesStatement;
+
+public class SelectValidator implements SelectVisitor, SelectItemVisitor, FromItemVisitor, PivotVisitor, Validation {
+
+ protected Map> errors;
+ private ExpressionValidator expressionVisitor;
+
+ public SelectValidator() {
+ this(new ExpressionValidator(), new EnumMap<>(DatabaseType.class));
+ }
+
+ public SelectValidator(ExpressionValidator expressionVisitor, Map> errors) {
+ this.errors = errors;
+ this.expressionVisitor = expressionVisitor;
+ }
+
+ @Override
+ public void visit(PlainSelect plainSelect) {
+ // if (plainSelect.isUseBrackets()) {
+ // errors.append("(");
+ // }
+ // errors.append("SELECT ");
+ //
+ // if (plainSelect.getMySqlHintStraightJoin()) {
+ // errors.append("STRAIGHT_JOIN ");
+ // }
+ //
+ // OracleHint hint = plainSelect.getOracleHint();
+ // if (hint != null) {
+ // errors.append(hint).append(" ");
+ // }
+ //
+ // Skip skip = plainSelect.getSkip();
+ // if (skip != null) {
+ // errors.append(skip).append(" ");
+ // }
+ //
+ // First first = plainSelect.getFirst();
+ // if (first != null) {
+ // errors.append(first).append(" ");
+ // }
+ //
+ // if (plainSelect.getDistinct() != null) {
+ // if (plainSelect.getDistinct().isUseUnique()) {
+ // errors.append("UNIQUE ");
+ // } else {
+ // errors.append("DISTINCT ");
+ // }
+ // if (plainSelect.getDistinct().getOnSelectItems() != null) {
+ // errors.append("ON (");
+ // for (Iterator iter = plainSelect.getDistinct().getOnSelectItems().
+ // iterator(); iter.hasNext();) {
+ // SelectItem selectItem = iter.next();
+ // selectItem.accept(this);
+ // if (iter.hasNext()) {
+ // errors.append(", ");
+ // }
+ // }
+ // errors.append(") ");
+ // }
+ //
+ // }
+ //
+ // Top top = plainSelect.getTop();
+ // if (top != null) {
+ // errors.append(top).append(" ");
+ // }
+ //
+ // if (plainSelect.getMySqlSqlNoCache()) {
+ // errors.append("SQL_NO_CACHE").append(" ");
+ // }
+ //
+ // if (plainSelect.getMySqlSqlCalcFoundRows()) {
+ // errors.append("SQL_CALC_FOUND_ROWS").append(" ");
+ // }
+ //
+ // for (Iterator iter = plainSelect.getSelectItems().iterator(); iter.hasNext();) {
+ // SelectItem selectItem = iter.next();
+ // selectItem.accept(this);
+ // if (iter.hasNext()) {
+ // errors.append(", ");
+ // }
+ // }
+ //
+ // if (plainSelect.getIntoTables() != null) {
+ // errors.append(" INTO ");
+ // for (Iterator iter = plainSelect.getIntoTables().iterator(); iter.hasNext();) {
+ // visit(iter.next());
+ // if (iter.hasNext()) {
+ // errors.append(", ");
+ // }
+ // }
+ // }
+ //
+ // if (plainSelect.getFromItem() != null) {
+ // errors.append(" FROM ");
+ // plainSelect.getFromItem().accept(this);
+ // }
+ //
+ // if (plainSelect.getJoins() != null) {
+ // for (Join join : plainSelect.getJoins()) {
+ // deparseJoin(join);
+ // }
+ // }
+ //
+ // if (plainSelect.getKsqlWindow() != null) {
+ // errors.append(" WINDOW ");
+ // errors.append(plainSelect.getKsqlWindow().toString());
+ // }
+
+ if (plainSelect.getWhere() != null) {
+ plainSelect.getWhere().accept(expressionVisitor);
+ }
+
+ // if (plainSelect.getOracleHierarchical() != null) {
+ // plainSelect.getOracleHierarchical().accept(expressionVisitor);
+ // }
+ //
+ // if (plainSelect.getGroupBy() != null) {
+ // errors.append(" ");
+ // new GroupByDeParser(expressionVisitor, errors).deParse(plainSelect.getGroupBy());
+ // }
+ //
+ // if (plainSelect.getHaving() != null) {
+ // errors.append(" HAVING ");
+ // plainSelect.getHaving().accept(expressionVisitor);
+ // }
+ //
+ // if (plainSelect.getOrderByElements() != null) {
+ // new OrderByDeParser(expressionVisitor, errors).
+ // deParse(plainSelect.isOracleSiblings(), plainSelect.getOrderByElements());
+ // }
+ //
+ // if (plainSelect.getLimit() != null) {
+ // new LimitDeparser(errors).deParse(plainSelect.getLimit());
+ // }
+ // if (plainSelect.getOffset() != null) {
+ // deparseOffset(plainSelect.getOffset());
+ // }
+ // if (plainSelect.getFetch() != null) {
+ // deparseFetch(plainSelect.getFetch());
+ // }
+ // if (plainSelect.isForUpdate()) {
+ // errors.append(" FOR UPDATE");
+ // if (plainSelect.getForUpdateTable() != null) {
+ // errors.append(" OF ").append(plainSelect.getForUpdateTable());
+ // }
+ // if (plainSelect.getWait() != null) {
+ // // wait's toString will do the formatting for us
+ // errors.append(plainSelect.getWait());
+ // }
+ // if (plainSelect.isNoWait()) {
+ // errors.append(" NOWAIT");
+ // }
+ // }
+ // if (plainSelect.getOptimizeFor() != null) {
+ // deparseOptimizeFor(plainSelect.getOptimizeFor());
+ // }
+ // if (plainSelect.getForXmlPath() != null) {
+ // errors.append(" FOR XML PATH(").append(plainSelect.getForXmlPath()).append(")");
+ // }
+ // if (plainSelect.isUseBrackets()) {
+ // errors.append(")");
+ // }
+ }
+
+ @Override
+ public void visit(AllTableColumns allTableColumns) {
+ // errors.append(allTableColumns.getTable().getFullyQualifiedName()).append(".*");
+ }
+
+ @Override
+ public void visit(SelectExpressionItem selectExpressionItem) {
+ // selectExpressionItem.getExpression().accept(expressionVisitor);
+ // if (selectExpressionItem.getAlias() != null) {
+ // errors.append(selectExpressionItem.getAlias().toString());
+ // }
+ }
+
+ @Override
+ public void visit(SubSelect subSelect) {
+ // errors.append("(");
+ // if (subSelect.getWithItemsList() != null && !subSelect.getWithItemsList().isEmpty()) {
+ // errors.append("WITH ");
+ // for (Iterator iter = subSelect.getWithItemsList().iterator(); iter.hasNext();) {
+ // WithItem withItem = iter.next();
+ // withItem.accept(this);
+ // if (iter.hasNext()) {
+ // errors.append(",");
+ // }
+ // errors.append(" ");
+ // }
+ // }
+ // subSelect.getSelectBody().accept(this);
+ // errors.append(")");
+ // Alias alias = subSelect.getAlias();
+ // if (alias != null) {
+ // errors.append(alias.toString());
+ // }
+ // Pivot pivot = subSelect.getPivot();
+ // if (pivot != null) {
+ // pivot.accept(this);
+ // }
+ }
+
+ @Override
+ public void visit(Table tableName) {
+ // errors.append(tableName.getFullyQualifiedName());
+ // Alias alias = tableName.getAlias();
+ // if (alias != null) {
+ // errors.append(alias);
+ // }
+ // Pivot pivot = tableName.getPivot();
+ // if (pivot != null) {
+ // pivot.accept(this);
+ // }
+ // UnPivot unpivot = tableName.getUnPivot();
+ // if (unpivot != null) {
+ // unpivot.accept(this);
+ // }
+ // MySQLIndexHint indexHint = tableName.getIndexHint();
+ // if (indexHint != null) {
+ // errors.append(indexHint);
+ // }
+ // SQLServerHints sqlServerHints = tableName.getSqlServerHints();
+ // if (sqlServerHints != null) {
+ // errors.append(sqlServerHints);
+ // }
+ }
+
+ @Override
+ public void visit(Pivot pivot) {
+ // List forColumns = pivot.getForColumns();
+ // errors.append(" PIVOT (")
+ // .append(PlainSelect.getStringList(pivot.getFunctionItems()))
+ // .append(" FOR ")
+ // .append(PlainSelect.
+ // getStringList(forColumns, true, forColumns != null && forColumns.size() > 1)).
+ // append(" IN ")
+ // .append(PlainSelect.getStringList(pivot.getInItems(), true, true))
+ // .append(")");
+ // if (pivot.getAlias() != null) {
+ // errors.append(pivot.getAlias().toString());
+ // }
+ }
+
+ @Override
+ public void visit(UnPivot unpivot) {
+ // boolean showOptions = unpivot.getIncludeNullsSpecified();
+ // boolean includeNulls = unpivot.getIncludeNulls();
+ // List unpivotForClause = unpivot.getUnPivotForClause();
+ // errors.append(" UNPIVOT")
+ // .append(showOptions && includeNulls ? " INCLUDE NULLS" : "")
+ // .append(showOptions && !includeNulls ? " EXCULDE NULLS" : "")
+ // .append(" (")
+ // .append(unpivot.getUnPivotClause())
+ // .append(" FOR ").append(PlainSelect.getStringList(unpivotForClause, true, unpivotForClause != null && unpivotForClause.size() > 1))
+ // .append(" IN ").append(PlainSelect.getStringList(unpivot.getUnPivotInClause(), true, true))
+ // .append(")");
+ }
+
+ @Override
+ public void visit(PivotXml pivot) {
+ // List forColumns = pivot.getForColumns();
+ // errors.append(" PIVOT XML (")
+ // .append(PlainSelect.getStringList(pivot.getFunctionItems()))
+ // .append(" FOR ")
+ // .append(PlainSelect.
+ // getStringList(forColumns, true, forColumns != null && forColumns.size() > 1)).
+ // append(" IN (");
+ // if (pivot.isInAny()) {
+ // errors.append("ANY");
+ // } else if (pivot.getInSelect() != null) {
+ // errors.append(pivot.getInSelect());
+ // } else {
+ // errors.append(PlainSelect.getStringList(pivot.getInItems()));
+ // }
+ // errors.append("))");
+ }
+
+ public void deparseOffset(Offset offset) {
+ // // OFFSET offset
+ // // or OFFSET offset (ROW | ROWS)
+ // if (offset.getOffsetJdbcParameter() != null) {
+ // errors.append(" OFFSET ").append(offset.getOffsetJdbcParameter());
+ // } else {
+ // errors.append(" OFFSET ");
+ // errors.append(offset.getOffset());
+ // }
+ // if (offset.getOffsetParam() != null) {
+ // errors.append(" ").append(offset.getOffsetParam());
+ // }
+
+ }
+
+ public void deparseFetch(Fetch fetch) {
+ // // FETCH (FIRST | NEXT) row_count (ROW | ROWS) ONLY
+ // errors.append(" FETCH ");
+ // if (fetch.isFetchParamFirst()) {
+ // errors.append("FIRST ");
+ // } else {
+ // errors.append("NEXT ");
+ // }
+ // if (fetch.getFetchJdbcParameter() != null) {
+ // errors.append(fetch.getFetchJdbcParameter().toString());
+ // } else {
+ // errors.append(fetch.getRowCount());
+ // }
+ // errors.append(" ").append(fetch.getFetchParam()).append(" ONLY");
+
+ }
+
+ // public ExpressionVisitor getExpressionVisitor() {
+ // return expressionVisitor;
+ // }
+ //
+ // public void setExpressionVisitor(ExpressionVisitor visitor) {
+ // expressionVisitor = visitor;
+ // }
+
+ @Override
+ public void visit(SubJoin subjoin) {
+ // errors.append("(");
+ // subjoin.getLeft().accept(this);
+ // for (Join join : subjoin.getJoinList()) {
+ // deparseJoin(join);
+ // }
+ // errors.append(")");
+ //
+ // if (subjoin.getPivot() != null) {
+ // subjoin.getPivot().accept(this);
+ // }
+ }
+
+ public void deparseJoin(Join join) {
+ // if (join.isSimple() && join.isOuter()) {
+ // errors.append(", OUTER ");
+ // } else if (join.isSimple()) {
+ // errors.append(", ");
+ // } else {
+ //
+ // if (join.isRight()) {
+ // errors.append(" RIGHT");
+ // } else if (join.isNatural()) {
+ // errors.append(" NATURAL");
+ // } else if (join.isFull()) {
+ // errors.append(" FULL");
+ // } else if (join.isLeft()) {
+ // errors.append(" LEFT");
+ // } else if (join.isCross()) {
+ // errors.append(" CROSS");
+ // }
+ //
+ // if (join.isOuter()) {
+ // errors.append(" OUTER");
+ // } else if (join.isInner()) {
+ // errors.append(" INNER");
+ // } else if (join.isSemi()) {
+ // errors.append(" SEMI");
+ // }
+ //
+ // if (join.isStraight()) {
+ // errors.append(" STRAIGHT_JOIN ");
+ // } else if (join.isApply()) {
+ // errors.append(" APPLY ");
+ // } else {
+ // errors.append(" JOIN ");
+ // }
+ //
+ // }
+ //
+ // FromItem fromItem = join.getRightItem();
+ // fromItem.accept(this);
+ // if (join.isWindowJoin()) {
+ // errors.append(" WITHIN ");
+ // errors.append(join.getJoinWindow().toString());
+ // }
+ // if (join.getOnExpression() != null) {
+ // errors.append(" ON ");
+ // join.getOnExpression().accept(expressionVisitor);
+ // }
+ // if (join.getUsingColumns() != null) {
+ // errors.append(" USING (");
+ // for (Iterator iterator = join.getUsingColumns().iterator(); iterator.hasNext();) {
+ // Column column = iterator.next();
+ // errors.append(column.toString());
+ // if (iterator.hasNext()) {
+ // errors.append(", ");
+ // }
+ // }
+ // errors.append(")");
+ // }
+
+ }
+
+ @Override
+ public void visit(SetOperationList list) {
+ // for (int i = 0; i < list.getSelects().size(); i++) {
+ // if (i != 0) {
+ // errors.append(' ').append(list.getOperations().get(i - 1)).append(' ');
+ // }
+ // boolean brackets = list.getBrackets() == null || list.getBrackets().get(i);
+ // if (brackets) {
+ // errors.append("(");
+ // }
+ // list.getSelects().get(i).accept(this);
+ // if (brackets) {
+ // errors.append(")");
+ // }
+ // }
+ // if (list.getOrderByElements() != null) {
+ // new OrderByDeParser(expressionVisitor, errors).deParse(list.getOrderByElements());
+ // }
+ //
+ // if (list.getLimit() != null) {
+ // new LimitDeparser(errors).deParse(list.getLimit());
+ // }
+ // if (list.getOffset() != null) {
+ // deparseOffset(list.getOffset());
+ // }
+ // if (list.getFetch() != null) {
+ // deparseFetch(list.getFetch());
+ // }
+ }
+
+ @Override
+ public void visit(WithItem withItem) {
+ // if (withItem.isRecursive()) {
+ // errors.append("RECURSIVE ");
+ // }
+ // errors.append(withItem.getName());
+ // if (withItem.getWithItemList() != null) {
+ // errors.append(" ").append(PlainSelect.
+ // getStringList(withItem.getWithItemList(), true, true));
+ // }
+ // errors.append(" AS (");
+ // withItem.getSelectBody().accept(this);
+ // errors.append(")");
+ }
+
+ @Override
+ public void visit(LateralSubSelect lateralSubSelect) {
+ // errors.append(lateralSubSelect.toString());
+ }
+
+ @Override
+ public void visit(ValuesList valuesList) {
+ // errors.append(valuesList.toString());
+ }
+
+ @Override
+ public void visit(AllColumns allColumns) {
+ // errors.append('*');
+ }
+
+ @Override
+ public void visit(TableFunction tableFunction) {
+ // errors.append(tableFunction.toString());
+ }
+
+ @Override
+ public void visit(ParenthesisFromItem parenthesis) {
+ // errors.append("(");
+ // parenthesis.getFromItem().accept(this);
+ // errors.append(")");
+ // if (parenthesis.getAlias() != null) {
+ // errors.append(parenthesis.getAlias().toString());
+ // }
+ }
+
+ @Override
+ public void visit(ValuesStatement values) {
+ // new ValuesStatementDeParser(expressionVisitor, errors).deParse(values);
+ }
+
+ private void deparseOptimizeFor(OptimizeFor optimizeFor) {
+ // errors.append(" OPTIMIZE FOR ");
+ // errors.append(optimizeFor.getRowCount());
+ // errors.append(" ROWS");
+ }
+
+ @Override
+ public Map> getValidationErrors() {
+ Validation.mergeTo(expressionVisitor.getValidationErrors(), errors);
+ return errors;
+ }
+}
diff --git a/src/main/java/net/sf/jsqlparser/util/validation/StatementValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/StatementValidator.java
new file mode 100644
index 000000000..4ad1b1905
--- /dev/null
+++ b/src/main/java/net/sf/jsqlparser/util/validation/StatementValidator.java
@@ -0,0 +1,318 @@
+/*-
+ * #%L
+ * JSQLParser library
+ * %%
+ * Copyright (C) 2004 - 2019 JSQLParser
+ * %%
+ * Dual licensed under GNU LGPL 2.1 or Apache License 2.0
+ * #L%
+ */
+package net.sf.jsqlparser.util.validation;
+
+import java.util.EnumMap;
+import java.util.Map;
+import java.util.Set;
+import net.sf.jsqlparser.statement.Block;
+import net.sf.jsqlparser.statement.Commit;
+import net.sf.jsqlparser.statement.CreateFunctionalStatement;
+import net.sf.jsqlparser.statement.DeclareStatement;
+import net.sf.jsqlparser.statement.DescribeStatement;
+import net.sf.jsqlparser.statement.ExplainStatement;
+import net.sf.jsqlparser.statement.SetStatement;
+import net.sf.jsqlparser.statement.ShowColumnsStatement;
+import net.sf.jsqlparser.statement.ShowStatement;
+import net.sf.jsqlparser.statement.StatementVisitor;
+import net.sf.jsqlparser.statement.Statements;
+import net.sf.jsqlparser.statement.UseStatement;
+import net.sf.jsqlparser.statement.alter.Alter;
+import net.sf.jsqlparser.statement.alter.sequence.AlterSequence;
+import net.sf.jsqlparser.statement.comment.Comment;
+import net.sf.jsqlparser.statement.create.index.CreateIndex;
+import net.sf.jsqlparser.statement.create.schema.CreateSchema;
+import net.sf.jsqlparser.statement.create.sequence.CreateSequence;
+import net.sf.jsqlparser.statement.create.table.CreateTable;
+import net.sf.jsqlparser.statement.create.view.AlterView;
+import net.sf.jsqlparser.statement.create.view.CreateView;
+import net.sf.jsqlparser.statement.delete.Delete;
+import net.sf.jsqlparser.statement.drop.Drop;
+import net.sf.jsqlparser.statement.execute.Execute;
+import net.sf.jsqlparser.statement.grant.Grant;
+import net.sf.jsqlparser.statement.insert.Insert;
+import net.sf.jsqlparser.statement.merge.Merge;
+import net.sf.jsqlparser.statement.replace.Replace;
+import net.sf.jsqlparser.statement.select.Select;
+import net.sf.jsqlparser.statement.truncate.Truncate;
+import net.sf.jsqlparser.statement.update.Update;
+import net.sf.jsqlparser.statement.upsert.Upsert;
+import net.sf.jsqlparser.statement.values.ValuesStatement;
+
+public class StatementValidator implements StatementVisitor, Validation {
+
+ protected Map> errors;
+ private ExpressionValidator expressionValidator;
+ private SelectValidator selectValidator;
+
+ public StatementValidator() {
+ this(new EnumMap<>(DatabaseType.class));
+ }
+
+ public StatementValidator(Map> errors) {
+ this(new ExpressionValidator(), new SelectValidator(), errors);
+ }
+
+ public StatementValidator(ExpressionValidator expressionDeParser, SelectValidator selectValidator,
+ Map> errors) {
+ this.expressionValidator = expressionDeParser;
+ this.selectValidator = selectValidator;
+ this.errors = errors;
+ }
+
+ @Override
+ public void visit(CreateIndex createIndex) {
+ // CreateIndexDeParser createIndexDeParser = new CreateIndexDeParser(errors);
+ // createIndexDeParser.deParse(createIndex);
+ }
+
+ @Override
+ public void visit(CreateTable createTable) {
+ // CreateTableDeParser createTableDeParser = new CreateTableDeParser(this, buffer);
+ // createTableDeParser.deParse(createTable);
+ }
+
+ @Override
+ public void visit(CreateView createView) {
+ // CreateViewDeParser createViewDeParser = new CreateViewDeParser(buffer);
+ // createViewDeParser.deParse(createView);
+ }
+
+ @Override
+ public void visit(AlterView alterView) {
+ // AlterViewDeParser alterViewDeParser = new AlterViewDeParser(buffer);
+ // alterViewDeParser.deParse(alterView);
+ }
+
+ @Override
+ public void visit(Delete delete) {
+ // selectValidator.setBuffer(buffer);
+ // expressionDeParser.setSelectVisitor(selectValidator);
+ // expressionDeParser.setBuffer(buffer);
+ // selectValidator.setExpressionVisitor(expressionDeParser);
+ // DeleteDeParser deleteDeParser = new DeleteDeParser(expressionDeParser, buffer);
+ // deleteDeParser.deParse(delete);
+ }
+
+ @Override
+ public void visit(Drop drop) {
+ // DropDeParser dropDeParser = new DropDeParser(buffer);
+ // dropDeParser.deParse(drop);
+ }
+
+ @Override
+ public void visit(Insert insert) {
+ // selectValidator.setBuffer(buffer);
+ // expressionDeParser.setSelectVisitor(selectValidator);
+ // expressionDeParser.setBuffer(buffer);
+ // selectValidator.setExpressionVisitor(expressionDeParser);
+ // InsertDeParser insertDeParser = new InsertDeParser(expressionDeParser,
+ // selectValidator, buffer);
+ // insertDeParser.deParse(insert);
+ }
+
+ @Override
+ public void visit(Replace replace) {
+ // selectValidator.setBuffer(buffer);
+ // expressionDeParser.setSelectVisitor(selectValidator);
+ // expressionDeParser.setBuffer(buffer);
+ // selectValidator.setExpressionVisitor(expressionDeParser);
+ // ReplaceDeParser replaceDeParser = new ReplaceDeParser(expressionDeParser,
+ // selectValidator, buffer);
+ // replaceDeParser.deParse(replace);
+ }
+
+ @Override
+ public void visit(Select select) {
+ // selectValidator.setBuffer(errors);
+ // expressionDeParser.setSelectVisitor(selectValidator);
+ // expressionDeParser.setBuffer(errors);
+ // selectValidator.setExpressionVisitor(expressionDeParser);
+ // if (select.getWithItemsList() != null && !select.getWithItemsList().isEmpty()) {
+ // errors.append("WITH ");
+ // for (Iterator iter = select.getWithItemsList().iterator(); iter.hasNext();) {
+ // WithItem withItem = iter.next();
+ // withItem.accept(selectValidator);
+ // if (iter.hasNext()) {
+ // errors.append(",");
+ // }
+ // errors.append(" ");
+ // }
+ // }
+ select.getSelectBody().accept(selectValidator);
+ }
+
+ @Override
+ public void visit(Truncate truncate) {
+ // errors.append("TRUNCATE TABLE ");
+ // errors.append(truncate.getTable());
+ // if (truncate.getCascade()) {
+ // errors.append(" CASCADE");
+ // }
+ }
+
+ @Override
+ public void visit(Update update) {
+ // selectValidator.setBuffer(errors);
+ // expressionDeParser.setSelectVisitor(selectValidator);
+ // expressionDeParser.setBuffer(errors);
+ // UpdateDeParser updateDeParser = new UpdateDeParser(expressionDeParser, selectValidator, errors);
+ // selectValidator.setExpressionVisitor(expressionDeParser);
+ // updateDeParser.deParse(update);
+
+ }
+
+ @Override
+ public void visit(Alter alter) {
+ // AlterDeParser alterDeParser = new AlterDeParser(errors);
+ // alterDeParser.deParse(alter);
+ //
+ }
+
+ @Override
+ public void visit(Statements stmts) {
+ // stmts.accept(this);
+ }
+
+ @Override
+ public void visit(Execute execute) {
+ // selectValidator.setBuffer(errors);
+ // expressionDeParser.setSelectVisitor(selectValidator);
+ // expressionDeParser.setBuffer(errors);
+ // ExecuteDeParser executeDeParser = new ExecuteDeParser(expressionDeParser, errors);
+ // selectValidator.setExpressionVisitor(expressionDeParser);
+ // executeDeParser.deParse(execute);
+ }
+
+ @Override
+ public void visit(SetStatement set) {
+ // selectValidator.setBuffer(errors);
+ // expressionDeParser.setSelectVisitor(selectValidator);
+ // expressionDeParser.setBuffer(errors);
+ // SetStatementDeParser setStatementDeparser = new SetStatementDeParser(expressionDeParser, errors);
+ // selectValidator.setExpressionVisitor(expressionDeParser);
+ // setStatementDeparser.deParse(set);
+ }
+
+ @Override
+ public void visit(Merge merge) {
+ //TODO implementation of a deparser
+ // errors.append(merge.toString());
+ }
+
+ @Override
+ public void visit(Commit commit) {
+ // errors.append(commit.toString());
+ }
+
+ @Override
+ public void visit(Upsert upsert) {
+ // selectValidator.setBuffer(errors);
+ // expressionDeParser.setSelectVisitor(selectValidator);
+ // expressionDeParser.setBuffer(errors);
+ // selectValidator.setExpressionVisitor(expressionDeParser);
+ // UpsertDeParser upsertDeParser = new UpsertDeParser(expressionDeParser, selectValidator, errors);
+ // upsertDeParser.deParse(upsert);
+ }
+
+ @Override
+ public void visit(UseStatement use) {
+ // new UseStatementDeParser(errors).deParse(use);
+ }
+
+ @Override
+ public void visit(ShowColumnsStatement show) {
+ // new ShowColumnsStatementDeParser(errors).deParse(show);
+ }
+
+ @Override
+ public void visit(Block block) {
+ // errors.append("BEGIN\n");
+ // if (block.getStatements() != null) {
+ // for (Statement stmt : block.getStatements().getStatements()) {
+ // stmt.accept(this);
+ // errors.append(";\n");
+ // }
+ // }
+ // errors.append("END");
+ }
+
+ @Override
+ public void visit(Comment comment) {
+ // errors.append(comment.toString());
+ }
+
+ @Override
+ public void visit(ValuesStatement values) {
+ // expressionDeParser.setBuffer(errors);
+ // new ValuesStatementDeParser(expressionDeParser, errors).deParse(values);
+ }
+
+ @Override
+ public void visit(DescribeStatement describe) {
+ // errors.append("DESCRIBE ");
+ // errors.append(describe.getTable());
+ }
+
+ @Override
+ public void visit(ExplainStatement explain) {
+ // errors.append("EXPLAIN ");
+ // if (explain.getOptions() != null) {
+ // errors.append(explain.getOptions().values().stream().map(ExplainStatement.Option::formatOption)
+ // .collect(Collectors.joining(" ")));
+ // errors.append(" ");
+ // }
+ // explain.getStatement().accept(this);
+ }
+
+ @Override
+ public void visit(ShowStatement show) {
+ // new ShowStatementDeParser(errors).deParse(show);
+ }
+
+ @Override
+ public void visit(DeclareStatement declare) {
+ // expressionDeParser.setBuffer(errors);
+ // new DeclareStatementDeParser(expressionDeParser, errors).deParse(declare);
+ }
+
+ @Override
+ public void visit(Grant grant) {
+ // GrantDeParser grantDeParser = new GrantDeParser(errors);
+ // grantDeParser.deParse(grant);
+ }
+
+ @Override
+ public void visit(CreateSchema aThis) {
+ // errors.append(aThis.toString());
+ }
+
+ @Override
+ public void visit(CreateSequence createSequence) {
+ // new CreateSequenceDeParser(errors).deParse(createSequence);
+ }
+
+ @Override
+ public void visit(AlterSequence alterSequence) {
+ // new AlterSequenceDeParser(errors).deParse(alterSequence);
+ }
+
+ @Override
+ public void visit(CreateFunctionalStatement createFunctionalStatement) {
+ // errors.append(createFunctionalStatement.toString());
+ }
+
+ @Override
+ public Map> getValidationErrors() {
+ Validation.mergeTo(this.expressionValidator.getValidationErrors(), errors);
+ Validation.mergeTo(this.selectValidator.getValidationErrors(), errors);
+ return errors;
+ }
+}
diff --git a/src/main/java/net/sf/jsqlparser/util/validation/Validation.java b/src/main/java/net/sf/jsqlparser/util/validation/Validation.java
new file mode 100644
index 000000000..a79f73fc2
--- /dev/null
+++ b/src/main/java/net/sf/jsqlparser/util/validation/Validation.java
@@ -0,0 +1,102 @@
+package net.sf.jsqlparser.util.validation;
+
+import java.util.Arrays;
+import java.util.EnumMap;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+public interface Validation {
+
+ /**
+ * @param databaseTypes
+ * @return true
, if the given databaseTypes support this feature.
+ * false
otherwise.
+ */
+ default boolean isSupported() {
+ return getValidationErrors().isEmpty();
+ }
+
+ default boolean isSupported(DatabaseType... databaseTypes) {
+ return getValidationErrors(databaseTypes).isEmpty();
+ }
+
+ /**
+ * Overwrite this method, if the feature support is not given on any
+ * {@link DatabaseType}
+ *
+ * @param databaseTypes
+ * @return the requested databaseTypes mapped to a list of error-messages
+ * (containing hints to used sql-string
+ * snippets not supported).
+ */
+ public Map> getValidationErrors();
+
+ default Map> getValidationErrors(DatabaseType... databaseTypes) {
+ Map> map = new EnumMap<>(DatabaseType.class);
+
+ EnumSet notRequested = EnumSet.allOf(DatabaseType.class);
+ notRequested.removeAll(Arrays.asList(databaseTypes));
+
+ map.putAll(getValidationErrors());
+
+ for (DatabaseType type : notRequested) {
+ map.remove(type);
+ }
+ return map;
+ }
+
+ /**
+ * Utility-function to map all {@link DatabaseType}'s except the supported ones
+ * to error-messages (containing hints to used sql-string
+ * snippets not supported).
+ *
+ * @param databaseTypes
+ * @param unsupportedSqlOrFeature
+ * @return
+ */
+ static Map> mapAllExcept(EnumSet databaseTypes,
+ String... unsupportedSqlOrFeature) {
+ EnumSet set = EnumSet.allOf(DatabaseType.class);
+ set.removeAll(databaseTypes);
+ List asList = Arrays.asList(unsupportedSqlOrFeature);
+ return set.stream().collect(
+ Collectors.toMap(Function.identity(), k -> new HashSet<>(asList)));
+ }
+
+ /**
+ * Utility-function to map all {@link DatabaseType}'s except the supported ones
+ * to error-messages (containing hints to used sql-string
+ * snippets not supported).
+ *
+ * @param target
+ * @param databaseTypes
+ * @param unsupportedSqlOrFeature
+ * @return the given target-map containing the errors
+ */
+ static Map> mapAllExcept(Map> target,
+ EnumSet databaseTypes, String... unsupportedSqlOrFeature) {
+ return mergeTo(mapAllExcept(databaseTypes, unsupportedSqlOrFeature), target);
+ }
+
+ /**
+ * merge source-map to target-map
+ *
+ * @param source
+ * @param target
+ * @return
+ */
+ static Map> mergeTo(Map> source,
+ Map> target) {
+ for (Entry> errors : source.entrySet()) {
+ target.computeIfAbsent(errors.getKey(), k -> errors.getValue()).addAll(errors.getValue());
+ }
+ return target;
+ }
+
+}
diff --git a/src/test/java/net/sf/jsqlparser/validation/ValidationTest.java b/src/test/java/net/sf/jsqlparser/validation/ValidationTest.java
new file mode 100644
index 000000000..76af3303a
--- /dev/null
+++ b/src/test/java/net/sf/jsqlparser/validation/ValidationTest.java
@@ -0,0 +1,38 @@
+package net.sf.jsqlparser.validation;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import net.sf.jsqlparser.JSQLParserException;
+import net.sf.jsqlparser.parser.CCJSqlParserUtil;
+import net.sf.jsqlparser.statement.Statement;
+import net.sf.jsqlparser.util.validation.DatabaseType;
+import net.sf.jsqlparser.util.validation.StatementValidator;
+
+public class ValidationTest {
+
+ // public static class ValidationVisitor implements ModelVisitor
+ // {
+ //
+ // }
+
+ @Test
+ public void testValidaton() throws JSQLParserException {
+ String sql = "SELECT * FROM tab1, tab2 WHERE tab1.id (+) = tab2.ref";
+ Statement stmt = CCJSqlParserUtil.parse(sql);
+
+ StatementValidator validator = new StatementValidator();
+ stmt.accept(validator);
+
+ Map> unsupportedErrors = validator.getValidationErrors(DatabaseType.sqlserver);
+ assertNotNull(unsupportedErrors);
+ assertEquals(1, unsupportedErrors.size());
+ assertEquals(new HashSet<>(Arrays.asList("oldOracleJoinSyntax=1 not supported")),
+ unsupportedErrors.get(DatabaseType.sqlserver));
+ }
+
+}