gt:         	if (setQuery.getLimit() != null) {
context: /*
   * JBoss, Home of Professional Open Source.
   * See the COPYRIGHT.txt file distributed with this work for information
   * regarding copyright ownership.  Some portions may be licensed
   * to Red Hat, Inc. under one or more contributor license agreements.
   * 
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   * 
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   * 
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
   * 02110-1301 USA.
   */
  
  package org.teiid.query.validator;
  
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.LinkedList;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  import org.teiid.api.exception.query.QueryMetadataException;
  import org.teiid.api.exception.query.QueryValidatorException;
  import org.teiid.core.TeiidComponentException;
  import org.teiid.query.QueryPlugin;
  import org.teiid.query.metadata.QueryMetadataInterface;
  import org.teiid.query.metadata.SupportConstants;
  import org.teiid.query.optimizer.relational.PartitionAnalyzer;
  import org.teiid.query.resolver.util.ResolverUtil;
  import org.teiid.query.sql.lang.Command;
  import org.teiid.query.sql.lang.Insert;
  import org.teiid.query.sql.lang.Query;
  import org.teiid.query.sql.lang.SetQuery;
  import org.teiid.query.sql.lang.UnaryFromClause;
  import org.teiid.query.sql.symbol.Constant;
  import org.teiid.query.sql.symbol.ElementSymbol;
  import org.teiid.query.sql.symbol.Expression;
  import org.teiid.query.sql.symbol.GroupSymbol;
  import org.teiid.query.sql.util.SymbolMap;
  
  /**
   * <p> This visitor is used to validate updates through virtual groups. The command defining
   * the virtual group is always a <code>Query</code>. This object visits various parts of
   * this <code>Query</code> and verifies if the virtual group definition will allows it to be
   * updated.</p>
   */
  public class UpdateValidator {
  	
  	public enum UpdateType {
  		/**
  		 * The default handling should be used
  		 */
  		INHERENT, 
  		/**
  		 * An instead of trigger (TriggerAction) has been defined
  		 */
  		INSTEAD_OF
  	}
  	
  	public static class UpdateMapping {
  		private GroupSymbol group;
  		private GroupSymbol correlatedName;
  		private Map<ElementSymbol, ElementSymbol> updatableViewSymbols = new HashMap<ElementSymbol, ElementSymbol>();
  		private boolean insertAllowed = false;
  		private boolean updateAllowed = false;
  		
  		public Map<ElementSymbol, ElementSymbol> getUpdatableViewSymbols() {
  			return updatableViewSymbols;
  		}
  		
  		public boolean isInsertAllowed() {
  			return insertAllowed;
  		}
  		
  		public boolean isUpdateAllowed() {
  			return updateAllowed;
  		}
  		
  		public GroupSymbol getGroup() {
  			return group;
  		}
  		
  		public GroupSymbol getCorrelatedName() {
  			return correlatedName;
  		}
  	}
  	
  	public static class UpdateInfo {
  		private Map<String, UpdateMapping> updatableGroups = new HashMap<String, UpdateMapping>();
  		private boolean isSimple = true;
  		private UpdateMapping deleteTarget;
  		private UpdateType updateType;
  		private String updateValidationError;
  		private UpdateType deleteType;
  		private String deleteValidationError;
  		private UpdateType insertType;
  		private String insertValidationError;
  		private Query view;
  		private Map<ElementSymbol, List<Set<Constant>>> partitionInfo;
  		private List<UpdateInfo> unionBranches = new LinkedList<UpdateInfo>();
  		
  		public Map<ElementSymbol, List<Set<Constant>>> getPartitionInfo() {
  			return partitionInfo;
  		}
  		 
  		public boolean isSimple() {
  			return isSimple;
  		}
  		
  		public UpdateMapping getDeleteTarget() {
  			return deleteTarget;
  		}
  		
  		public boolean isInherentDelete() {
  			return deleteType == UpdateType.INHERENT;
  		}
  		
  		public boolean isInherentInsert() {
  			return insertType == UpdateType.INHERENT;
  		}
  		
  		public boolean isInherentUpdate() {
  			return updateType == UpdateType.INHERENT;
  		}
  		
  		public UpdateType getUpdateType() {
  			return updateType;
  		}
  		
  		public UpdateType getDeleteType() {
  			return deleteType;
  		}
  		
  		public boolean hasValidUpdateMapping(Collection<ElementSymbol> updateCols) {
  			if (findUpdateMapping(updateCols, false) == null) {
  				return false;
  			}
  			for (UpdateInfo info : this.unionBranches) {
  				if (info.findUpdateMapping(updateCols, false) == null) {
  					return false;
  				}
  			}
  			return true;
  		}
  		
  		public UpdateMapping findUpdateMapping(Collection<ElementSymbol> updateCols, boolean insert) {
  			if (updateCols.isEmpty() && this.updatableGroups.size() > 1) {
  				return null;
  			}
  			for (UpdateMapping entry : this.updatableGroups.values()) {
  				if (((insert && entry.insertAllowed) || (!insert && entry.updateAllowed)) && entry.updatableViewSymbols.keySet().containsAll(updateCols)) {
  					return entry;
  				}
  			}
  			return null;
  		}
  		
  		public UpdateMapping findInsertUpdateMapping(Insert insert, boolean rewrite) throws QueryValidatorException {
  			if (getUnionBranches().isEmpty()) {
  				return findUpdateMapping(insert.getVariables(), true);	
  			}
  			if (insert.getQueryExpression() != null) {
  				//TODO: this could be done in a loop, see about adding a validation
  				 throw new QueryValidatorException(QueryPlugin.Event.TEIID30239, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30239, insert.getGroup()));
  			}
  			int partition = -1;
  			List<ElementSymbol> filteredColumns = new LinkedList<ElementSymbol>();
  			for (Map.Entry<ElementSymbol, List<Set<Constant>>> entry : partitionInfo.entrySet()) {
  				int index = insert.getVariables().indexOf(entry.getKey());
  				if (index == -1) {
  					continue;
  				}
  				Expression value = (Expression)insert.getValues().get(index);
  				if (!(value instanceof Constant)) {
  					continue;
  				}
  				for (int i = 0; i < entry.getValue().size(); i++) {
  					if (entry.getValue().get(i).contains(value)) {
  						if (entry.getValue().get(i).size() == 1) {
  							filteredColumns.add(entry.getKey());
  						}
  						if (partition == -1) {
  							partition = i;
  						} else if (partition != i) {
  							throw new QueryValidatorException(QueryPlugin.Event.TEIID30240, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30240, insert.getGroup(), insert.getVariables()));
  						}
  					}
  				}
  			}
  			if (partition == -1) {
  				 throw new QueryValidatorException(QueryPlugin.Event.TEIID30241, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30241, insert.getGroup(), insert.getVariables()));
  			}
  			UpdateInfo info = this;
  			if (partition > 0) {
  				info = info.getUnionBranches().get(partition - 1);
  			}
  			List<ElementSymbol> variables = new ArrayList<ElementSymbol>(insert.getVariables());
  			variables.removeAll(filteredColumns);
  			UpdateMapping mapping = info.findUpdateMapping(variables, true);
  			if (rewrite && mapping != null && !filteredColumns.isEmpty()) {
  				for (ElementSymbol elementSymbol : filteredColumns) {
  					if (mapping.getUpdatableViewSymbols().containsKey(elementSymbol)) {
  						continue;
  					}
  					int index = insert.getVariables().indexOf(elementSymbol);
  					insert.getVariables().remove(index);
  					if (rewrite) {
  						insert.getValues().remove(index);
  					}
  				}
  			}
  			return mapping;
  		}
  		
  		public Query getViewDefinition() {
  			return view;
  		}
  		
  		public String getDeleteValidationError() {
  			return deleteValidationError;
  		}
  		
  		public String getInsertValidationError() {
  			return insertValidationError;
  		}
  		
  		public String getUpdateValidationError() {
  			return updateValidationError;
  		}
  		
  		public List<UpdateInfo> getUnionBranches() {
  			return unionBranches;
  		}
  
  		private void setUpdateValidationError(String updateValidationError) {
  			if (this.updateValidationError == null) {
  				this.updateValidationError = updateValidationError;
  			}
  		}
  
  		private void setInsertValidationError(String insertValidationError) {
  			if (this.insertValidationError == null) {
  				this.insertValidationError = insertValidationError;
  			}
  		}
  
  		private void setDeleteValidationError(String deleteValidationError) {
  			if (this.deleteValidationError == null) {
  				this.deleteValidationError = deleteValidationError;
  			}
  		}
  		
  	}
  	
  	private QueryMetadataInterface metadata;
  	private UpdateInfo updateInfo = new UpdateInfo();
  	
  	private ValidatorReport report = new ValidatorReport();
  	private ValidatorReport insertReport = new ValidatorReport();
  	private ValidatorReport updateReport = new ValidatorReport();
  	private ValidatorReport deleteReport = new ValidatorReport();
  	
  	public UpdateValidator(QueryMetadataInterface qmi, UpdateType insertType, UpdateType updateType, UpdateType deleteType) {
  		this.metadata = qmi;
  		this.updateInfo.deleteType = deleteType;
  		this.updateInfo.insertType = insertType;
  		this.updateInfo.updateType = updateType;
  	}
  		
  	public UpdateInfo getUpdateInfo() {
  		return updateInfo;
  	}
  	
  	public ValidatorReport getReport() {
  		return report;
  	}
  	
  	public ValidatorReport getDeleteReport() {
  		return deleteReport;
  	}
  	
  	public ValidatorReport getInsertReport() {
  		return insertReport;
  	}
  	
  	public ValidatorReport getUpdateReport() {
  		return updateReport;
  	}
  	
  	private void handleValidationError(String error, boolean update, boolean insert, boolean delete) {
  		if (update && insert && delete) {
  			report.handleValidationError(error);
  			updateInfo.setUpdateValidationError(error);
  			updateInfo.setInsertValidationError(error);
  			updateInfo.setDeleteValidationError(error);
  		} else {
  			if (update) {
  				updateReport.handleValidationError(error);
  				updateInfo.setUpdateValidationError(error);
  			}
  			if (insert) {
  				insertReport.handleValidationError(error);
  				updateInfo.setInsertValidationError(error);
  			}
  			if (delete) {
  				deleteReport.handleValidationError(error);
  				updateInfo.setDeleteValidationError(error);
  			}
  		}
  	}
  	
      public void validate(Command command, List<ElementSymbol> viewSymbols) throws QueryMetadataException, TeiidComponentException {
      	if (this.updateInfo.deleteType != UpdateType.INHERENT && this.updateInfo.updateType != UpdateType.INHERENT && this.updateInfo.insertType != UpdateType.INHERENT) {
      		return;
      	}
      	if (command instanceof SetQuery) {
      		SetQuery setQuery = (SetQuery)command;
  