/*******************************************************************************
* Copyright © 2011, 2013 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*
*******************************************************************************/
package org.eclipse.edt.mof.eglx.persistence.sql.validation;
import org.eclipse.edt.compiler.core.IEGLConstants;
import org.eclipse.edt.compiler.core.ast.AbstractASTVisitor;
import org.eclipse.edt.compiler.core.ast.DeleteStatement;
import org.eclipse.edt.compiler.core.ast.Expression;
import org.eclipse.edt.compiler.core.ast.ForExpressionClause;
import org.eclipse.edt.compiler.core.ast.FromOrToExpressionClause;
import org.eclipse.edt.compiler.core.ast.UsingClause;
import org.eclipse.edt.compiler.core.ast.UsingKeysClause;
import org.eclipse.edt.compiler.core.ast.WithExpressionClause;
import org.eclipse.edt.compiler.core.ast.WithInlineSQLClause;
import org.eclipse.edt.compiler.internal.core.builder.IMarker;
import org.eclipse.edt.compiler.internal.core.builder.IProblemRequestor;
import org.eclipse.edt.compiler.internal.core.lookup.ICompilerOptions;
import org.eclipse.edt.mof.egl.ArrayType;
import org.eclipse.edt.mof.egl.Type;
import org.eclipse.edt.mof.egl.utils.TypeUtils;
import org.eclipse.edt.mof.eglx.persistence.sql.ext.Utils;
import org.eclipse.edt.mof.eglx.persistence.sql.messages.SQLResourceKeys;
public class DeleteStatementValidator extends AbstractSqlStatementValidator {
DeleteStatement statement;
IProblemRequestor problemRequestor;
ICompilerOptions compilerOptions;
UsingClause using;
UsingKeysClause usingKeys;
FromOrToExpressionClause from;
WithInlineSQLClause withInline;
WithExpressionClause withExpression;
ForExpressionClause forExpression;
public DeleteStatementValidator(DeleteStatement statement, IProblemRequestor problemRequestor, ICompilerOptions compilerOptions) {
super();
this.statement = statement;
this.problemRequestor = problemRequestor;
this.compilerOptions = compilerOptions;
}
public void validate() {
initialize();
validateTarget();
validateDataSource();
validateFor();
}
private void validateTarget() {
Expression target = statement.getTarget();
if (target != null) {
Type targetType = target.resolveType();
if (targetType != null && TypeUtils.isPrimitive(targetType)) {
targetType = getContainingType(target.resolveMember());
}
// Target must be a data expression.
if (!isDataExpr(target)
//TODO arrays for delete not yet supported.
|| (targetType instanceof ArrayType)
) {
problemRequestor.acceptProblem(target,
SQLResourceKeys.SQL_TARGET_NOT_DATA_EXPR,
IMarker.SEVERITY_ERROR,
new String[] {},
SQLResourceKeys.getResourceBundleForKeys());
return;
}
//TODO associations not yet supported.
if (isAssociationExpression(target)) {
problemRequestor.acceptProblem(target,
SQLResourceKeys.SQL_ENTITY_ASSOCIATIONS_NOT_SUPPORTED,
IMarker.SEVERITY_ERROR,
new String[] {},
SQLResourceKeys.getResourceBundleForKeys());
return;
}
// Target must map to 1 table.
if (targetType != null && !isSingleTable(targetType)) {
problemRequestor.acceptProblem(target,
SQLResourceKeys.SQL_SINGLE_TABLE_REQUIRED,
IMarker.SEVERITY_ERROR,
new String[]{},
SQLResourceKeys.getResourceBundleForKeys());
return;
}
if (from != null) {
// If data source is SQLDataSource and there's no WITH or USING, target must have @Id on a field.
if (targetType != null
&& (withExpression == null && withInline == null && using == null && Utils.isSQLDataSource(from.getExpression().resolveType()))
&& !hasID(targetType)) {
problemRequestor.acceptProblem(target,
SQLResourceKeys.SQL_NO_ID_IN_TARGET_TYPE,
IMarker.SEVERITY_ERROR,
new String[] {targetType.getTypeSignature()},
SQLResourceKeys.getResourceBundleForKeys());
return;
}
}
}
}
private void validateDataSource() {
if (statement.getTarget() == null && from != null) {
Type type = from.getExpression().resolveType();
if (type != null && Utils.isSQLDataSource(type)) {
// WITH is required.
if (withInline == null && withExpression == null) {
problemRequestor.acceptProblem(statement,
SQLResourceKeys.SQL_WITH_STMT_REQUIRED_FOR_DELETE,
IMarker.SEVERITY_ERROR,
new String[]{"eglx.persistence.sql.SQLDataSource"},
SQLResourceKeys.getResourceBundleForKeys());
return;
}
}
else if (type != null && Utils.isSQLResultSet(type)) {
// USING, WITH, and FOR not allowed.
if (withInline != null || withExpression != null || forExpression != null || using != null) {
problemRequestor.acceptProblem(statement,
SQLResourceKeys.SQL_NO_WITH_FOR_USING,
IMarker.SEVERITY_ERROR,
new String[]{"eglx.persistence.sql.SQLResultSet"},
SQLResourceKeys.getResourceBundleForKeys());
return;
}
}
}
}
private void validateFor() {
if (forExpression != null) {
if (statement.getTarget() == null) {
// For not allowed if there's no target.
problemRequestor.acceptProblem(forExpression,
SQLResourceKeys.SQL_FOR_NOT_ALLOWED_WITHOUT_TARGET,
IMarker.SEVERITY_ERROR,
new String[] {},
SQLResourceKeys.getResourceBundleForKeys());
return;
}
else {
if (withExpression != null || withInline != null) {
problemRequestor.acceptProblem(statement,
SQLResourceKeys.SQL_DELETE_FOR_OR_WITH,
IMarker.SEVERITY_ERROR,
new String[] {},
SQLResourceKeys.getResourceBundleForKeys());
return;
}
Type type = forExpression.getExpression().resolveType();
if (type != null && (!isEntityWithID(type)
// TODO associations not supported yet. when they are, change it to the commented out line.
|| isAssociationExpression(forExpression.getExpression())
// && !isAssociationExpression(forExpression.getExpression())
)) {
problemRequestor.acceptProblem(forExpression.getExpression(),
SQLResourceKeys.SQL_FOR_TYPE_INVALID,
IMarker.SEVERITY_ERROR,
new String[] {forExpression.getExpression().getCanonicalString()},
SQLResourceKeys.getResourceBundleForKeys());
return;
}
if (type != null) {
// The type of the expression must match exactly the type of the action target.
Type targetType = statement.getTarget().resolveType();
if (targetType != null && !targetType.equals(type)) {
problemRequestor.acceptProblem(forExpression.getExpression(),
SQLResourceKeys.SQL_FOR_AND_TARGET_TYPES_MUST_MATCH,
IMarker.SEVERITY_ERROR,
new String[] {forExpression.getExpression().getCanonicalString(), type.getTypeSignature(), targetType.getTypeSignature()},
SQLResourceKeys.getResourceBundleForKeys());
return;
}
}
}
}
}
private void initialize() {
statement.accept(new AbstractASTVisitor() {
public boolean visit(WithInlineSQLClause withInlineSQLClause) {
if (withInline == null && withExpression == null) {
withInline = withInlineSQLClause;
}
else {
problemRequestor.acceptProblem(withInlineSQLClause,
IProblemRequestor.DUPE_OPTION,
new String[] { IEGLConstants.KEYWORD_DELETE.toUpperCase(), IEGLConstants.KEYWORD_WITH.toUpperCase()});
}
return false;
}
public boolean visit(WithExpressionClause withExpressionClause) {
if (withInline == null && withExpression == null) {
withExpression = withExpressionClause;
}
else {
problemRequestor.acceptProblem(withExpressionClause,
IProblemRequestor.DUPE_OPTION,
new String[] { IEGLConstants.KEYWORD_DELETE.toUpperCase(), IEGLConstants.KEYWORD_WITH.toUpperCase()});
}
return false;
}
public boolean visit(UsingClause usingClause) {
if (using == null) {
using = usingClause;
}
else {
problemRequestor.acceptProblem(usingClause,
IProblemRequestor.DUPE_OPTION,
new String[] { IEGLConstants.KEYWORD_DELETE.toUpperCase(), IEGLConstants.KEYWORD_USING.toUpperCase()});
}
return false;
}
public boolean visit(UsingKeysClause usingKeysClause) {
if (usingKeys == null) {
usingKeys = usingKeysClause;
}
else {
problemRequestor.acceptProblem(usingKeysClause,
IProblemRequestor.DUPE_OPTION,
new String[] { IEGLConstants.KEYWORD_DELETE.toUpperCase(), IEGLConstants.KEYWORD_USINGKEYS.toUpperCase()});
}
return false;
}
public boolean visit(FromOrToExpressionClause clause) {
if (from == null) {
from = clause;
}
else {
problemRequestor.acceptProblem(clause,
IProblemRequestor.DUPE_OPTION,
new String[] { IEGLConstants.KEYWORD_DELETE.toUpperCase(), IEGLConstants.KEYWORD_FROM.toUpperCase()});
}
return false;
}
public boolean visit(ForExpressionClause forExpressionClause) {
if (forExpression == null) {
forExpression = forExpressionClause;
}
else {
problemRequestor.acceptProblem(forExpressionClause,
IProblemRequestor.DUPE_OPTION,
new String[] { IEGLConstants.KEYWORD_DELETE.toUpperCase(), IEGLConstants.KEYWORD_FOR.toUpperCase()});
}
return false;
}
});
}
}