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

org.hibernate.hql.spi.id.cte.CteValuesListDeleteHandlerImpl Maven / Gradle / Ivy

There is a newer version: 7.0.0.Alpha1
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.spi.id.cte;

import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

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.spi.id.MultiTableBulkIdStrategy;
import org.hibernate.persister.collection.AbstractCollectionPersister;
import org.hibernate.sql.Delete;
import org.hibernate.type.CollectionType;
import org.hibernate.type.Type;

/**
 * Bulk-id delete handler that uses CTE and VALUES lists.
 *
 * @author Evandro Pires da Silva
 * @author Vlad Mihalcea
 */
public class CteValuesListDeleteHandlerImpl
		extends AbstractCteValuesListBulkIdHandler
		implements MultiTableBulkIdStrategy.DeleteHandler {

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

	public CteValuesListDeleteHandlerImpl(
			SessionFactoryImplementor factory,
			HqlSqlWalker walker) {
		this( factory, walker, null, null );
	}

	public CteValuesListDeleteHandlerImpl(
			SessionFactoryImplementor factory,
			HqlSqlWalker walker,
			String catalog,
			String schema) {
		super( factory, walker, catalog, schema );

		final String idSubselect = generateIdSubselect( getTargetedQueryable() );

		for ( Type type : getTargetedQueryable().getPropertyTypes() ) {
			if ( type.isCollectionType() ) {
				CollectionType cType = (CollectionType) type;
				AbstractCollectionPersister cPersister = (AbstractCollectionPersister) factory.getMetamodel().collectionPersister( cType.getRole() );
				if ( cPersister.isManyToMany() ) {
					deletes.add( generateDelete(
							cPersister.getTableName(),
							cPersister.getKeyColumnNames(),
							idSubselect,
							"bulk delete - m2m join table cleanup"
					) );
				}
			}
		}

		String[] tableNames = getTargetedQueryable().getConstraintOrderedTableNameClosure();
		String[][] columnNames = getTargetedQueryable().getContraintOrderedTableKeyColumnClosure();
		for ( int i = 0; i < tableNames.length; i++ ) {
			// TODO : an optimization here would be to consider cascade deletes and not gen those delete statements;
			//      the difficulty is the ordering of the tables here vs the cascade attributes on the persisters ->
			//          the table info gotten here should really be self-contained (i.e., a class representation
			//          defining all the needed attributes), then we could then get an array of those
			deletes.add( generateDelete( tableNames[i], columnNames[i], idSubselect, "bulk delete" ) );
		}
	}

	@Override
	public int execute(
			SharedSessionContractImplementor session,
			QueryParameters queryParameters) {

		CteValuesListBuilder values = prepareCteStatement( session, queryParameters );

		if ( !values.getIds().isEmpty() ) {
			// Start performing the deletes
			for ( String deleteSuffix : deletes ) {
				if ( deleteSuffix == null) {
					continue;
				}

				String delete = values.toStatement( deleteSuffix );

				try {
					try ( PreparedStatement ps = session
							.getJdbcCoordinator().getStatementPreparer()
							.prepareStatement( delete, false ) ) {
						int pos = 1;
						for ( Object[] result : values.getIds() ) {
							for ( Object column : result ) {
								ps.setObject( pos++, column );
							}
						}
						session
								.getJdbcCoordinator().getResultSetReturn()
								.executeUpdate( ps );
					}
				}
				catch ( SQLException e ) {
					throw convert( e, "error performing bulk delete", delete );
				}
			}
		}

		return values.getIds().size();
	}

	private String generateDelete(
			String tableName,
			String[] columnNames,
			String idSubselect,
			String comment) {
		final Delete delete = new Delete().setTableName( tableName ).setWhere(
				"(" + String.join( ", ", (CharSequence[]) columnNames ) + ") in ("
						+ idSubselect + ")" );
		if ( factory().getSessionFactoryOptions().isCommentsEnabled() ) {
			delete.setComment( comment );
		}
		return delete.toStatementString();
	}

	@Override
	public String[] getSqlStatements() {
		return deletes.toArray( new String[deletes.size()] );
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy