/***************************************************************************** * Copyright (C) 2008 EnterpriseDB Corporation. * Copyright (C) 2011 Stado Global Development Group. * * This file is part of Stado. * * Stado is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Stado 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Stado. If not, see <http://www.gnu.org/licenses/>. * * You can find Stado at http://www.stado.us * ****************************************************************************/ /* * DeleteForeignReferenceChecker.java * * */ package org.postgresql.stado.constraintchecker; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import org.postgresql.stado.common.util.XLogger; import org.postgresql.stado.engine.IExecutable; import org.postgresql.stado.engine.XDBSessionContext; import org.postgresql.stado.metadata.SysColumn; import org.postgresql.stado.metadata.SysConstraint; import org.postgresql.stado.metadata.SysForeignKey; import org.postgresql.stado.metadata.SysReference; import org.postgresql.stado.metadata.SysTable; import org.postgresql.stado.optimizer.QueryCondition; import org.postgresql.stado.parser.Parser; import org.postgresql.stado.parser.SqlSelect; /** * */ public class DeleteForeignReferenceChecker extends AbstractConstraintChecker { private static final XLogger logger = XLogger .getLogger(DeleteForeignReferenceChecker.class); private static final String TABLE_ALIAS1 = "t1"; private static final String TABLE_ALIAS2 = "t2"; private QueryCondition whereClause; /** * @param targetTable * @param client */ public DeleteForeignReferenceChecker(SysTable targetTable, QueryCondition whereClause, XDBSessionContext client) { super(targetTable, client); this.whereClause = whereClause; } /** * * @param columnsInvolved * @param keysToCheck * @return * @see org.postgresql.stado.ConstraintChecker.AbstractConstraintChecker#scanConstraints(java.util.Collection, * java.util.Collection) */ @Override protected Collection<SysColumn> scanConstraints( Collection<SysColumn> columnsInvolved, Collection keysToCheck) { final String method = "scanConstraints"; logger.entering(method, new Object[] { columnsInvolved, keysToCheck }); try { Collection<SysColumn> colsToAdd = new HashSet<SysColumn>(); Collection sysFks = targetTable.getSysReferences(); for (Iterator it = sysFks.iterator(); it.hasNext();) { SysReference reference = (SysReference) it.next(); if (reference.getDistributedCheck()) { Collection fks = reference.getForeignKeys(); for (Iterator iter = fks.iterator(); iter.hasNext();) { SysForeignKey fk = (SysForeignKey) iter.next(); SysColumn col = targetTable.getSysColumn(fk .getRefcolid()); if (!columnsInvolved.contains(col)) { colsToAdd.add(col); } } keysToCheck.add(reference); } } return colsToAdd; } finally { logger.exiting(method); } } /** * With temp table: SELECT 1 FROM <temp> t1 JOIN <foreign> t2 ON t1.<key> = * t2.<key> Without temp table: SELECT 1 FROM (SELECT <key> FROM <target> * [WHERE <condition>]) t1 JOIN <foreign> t2 ON t1.<key> = t2.<key> * * @see org.postgresql.stado.constraintchecker.AbstractConstraintChecker#prepareConstraint(java.lang.Object) */ @Override protected Map<IExecutable, ViolationCriteria> prepareConstraint( Object constraint) throws Exception { final String method = "prepareConstraint"; logger.entering(method, new Object[] {}); try { SysConstraint sysConstraint = ((SysReference) constraint) .getConstraint(); ViolationCriteria criteria = new ViolationCriteria(); criteria.violationType = VIOLATE_IF_NOT_EMPTY; criteria.message = sysConstraint.toString(); SysTable foreignTable = sysConstraint.getSysTable(); StringBuffer sbSelect = new StringBuffer("SELECT 1 FROM "); if (tempTable == null) { sbSelect.append("(SELECT "); Collection fks = ((SysReference) constraint).getForeignKeys(); for (Iterator iter = fks.iterator(); iter.hasNext();) { SysForeignKey fk = (SysForeignKey) iter.next(); SysColumn refCol = targetTable.getSysColumn(fk .getRefcolid()); sbSelect.append(refCol.getColName()).append(", "); } sbSelect.setLength(sbSelect.length() - 2); sbSelect.append(" FROM ").append(targetTable.getTableName()); if (whereClause != null) { sbSelect.append(" WHERE ").append( whereClause.rebuildString()); } sbSelect.append(") ").append(TABLE_ALIAS1); } else { sbSelect.append(tempTable.getTableName()); sbSelect.append(" ").append(TABLE_ALIAS1); } sbSelect.append(" JOIN ").append(foreignTable.getTableName()); sbSelect.append(" ").append(TABLE_ALIAS2); sbSelect.append(" ON "); Collection fks = ((SysReference) constraint).getForeignKeys(); for (Iterator iter = fks.iterator(); iter.hasNext();) { SysForeignKey fk = (SysForeignKey) iter.next(); SysColumn col = foreignTable.getSysColumn(fk.getColid()); SysColumn refCol = targetTable.getSysColumn(fk.getRefcolid()); sbSelect.append(TABLE_ALIAS1).append(".").append( refCol.getColName()).append("="); sbSelect.append(TABLE_ALIAS2).append(".").append( col.getColName()).append(" AND "); } sbSelect.setLength(sbSelect.length() - 5); Parser parser = new Parser(client); parser.parseStatement(sbSelect.toString()); SqlSelect select = (SqlSelect) parser.getSqlObject(); select.addSkipPermissionCheck(targetTable.getTableName()); select.addSkipPermissionCheck(foreignTable.getTableName()); select.prepare(); return Collections.singletonMap((IExecutable) select, criteria); } finally { logger.exiting(method); } } @Override public boolean isReadOnly() { // TODO Auto-generated method stub return false; } }