All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hibernate.hql.internal.ast.exec.DeleteExecutor Maven / Gradle / Ivy

There is a newer version: 6.5.0.CR2
Show newest version
/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
 * See the lgpl.txt file in the root directory or .
 */
package org.hibernate.hql.internal.ast.exec;

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

import org.hibernate.HibernateException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.hql.internal.ast.HqlSqlWalker;
import org.hibernate.hql.internal.ast.SqlGenerator;
import org.hibernate.hql.internal.ast.tree.DeleteStatement;
import org.hibernate.param.ParameterSpecification;
import org.hibernate.persister.collection.AbstractCollectionPersister;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.sql.Delete;
import org.hibernate.type.CollectionType;
import org.hibernate.type.Type;

import org.jboss.logging.Logger;

import antlr.RecognitionException;
import antlr.collections.AST;


/**
 * Provides deletions in addition to the basic SQL delete statement being executed.  Ex: cascading the delete into a
 * many-to-many join table.
 * 
 * @author Brett Meyer
 */
public class DeleteExecutor extends BasicExecutor {
	private static final Logger LOG = Logger.getLogger( DeleteExecutor.class );

	private final List deletes = new ArrayList<>();
	private List parameterSpecifications;

	public DeleteExecutor(HqlSqlWalker walker, Queryable persister) {
		super( walker, persister );
		
		final SessionFactoryImplementor factory = walker.getSessionFactoryHelper().getFactory();
		final Dialect dialect = factory.getJdbcServices().getJdbcEnvironment().getDialect();
		
		try {
			final DeleteStatement deleteStatement = (DeleteStatement) walker.getAST();
			
			final String idSubselectWhere;
			if ( deleteStatement.hasWhereClause() ) {
				final AST whereClause = deleteStatement.getWhereClause();
				final SqlGenerator gen = new SqlGenerator( factory );
				gen.whereClause( whereClause );
				parameterSpecifications = gen.getCollectedParameters();
				idSubselectWhere = gen.getSQL().length() > 7 ? gen.getSQL() : "";
			}
			else {
				parameterSpecifications = new ArrayList<>();
				idSubselectWhere = "";
			}
			
			// If many-to-many, delete the FK row in the collection table.
			for ( Type type : persister.getPropertyTypes() ) {
				if ( type.isCollectionType() ) {
					final CollectionType cType = (CollectionType) type;
					final AbstractCollectionPersister cPersister = (AbstractCollectionPersister) factory.getMetamodel().collectionPersister( cType.getRole() );
					if ( cPersister.isManyToMany() ) {
						if ( persister.getIdentifierColumnNames().length > 1
								&& !dialect.supportsTuplesInSubqueries() ) {
							LOG.warn(
									"This dialect is unable to cascade the delete into the many-to-many join table" +
									" when the entity has multiple primary keys.  Either properly setup cascading on" +
									" the constraints or manually clear the associations prior to deleting the entities."
							);
						}
						else {
							final String idSubselect = "(select "
									+ String.join( ", ", persister.getIdentifierColumnNames() ) + " from "
									+ persister.getTableName() + idSubselectWhere + ")";
							final String where = "(" + String.join( ", ", cPersister.getKeyColumnNames() )
									+ ") in " + idSubselect;
							final Delete delete = new Delete().setTableName( cPersister.getTableName() ).setWhere( where );
							if ( factory.getSessionFactoryOptions().isCommentsEnabled() ) {
								delete.setComment( "delete FKs in join table" );
							}
							deletes.add( delete.toStatementString() );
						}
					}
				}
			}
		}
		catch (RecognitionException e) {
			throw new HibernateException( "Unable to delete the FKs in the join table!", e );
		}
	}
	
	@Override
	public int execute(QueryParameters parameters, SharedSessionContractImplementor session) throws HibernateException {
		for (String delete : deletes) {
			doExecute( parameters, session, delete, parameterSpecifications );
		}
		
		// finally, execute the original sql statement
		return super.execute( parameters, session );
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy