/******************************************************************************* * Copyright (c) 1998, 2015 Oracle and/or its affiliates. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * Contributors: * Oracle - initial API and implementation from Oracle TopLink ******************************************************************************/ package org.eclipse.persistence.internal.expressions; import java.io.*; import java.util.HashMap; import java.util.Iterator; import org.eclipse.persistence.exceptions.*; import org.eclipse.persistence.expressions.*; import org.eclipse.persistence.queries.*; import org.eclipse.persistence.internal.sessions.AbstractSession; import java.util.Collection; import org.eclipse.persistence.internal.databaseaccess.DatabaseCall; import org.eclipse.persistence.internal.databaseaccess.DatasourcePlatform; import org.eclipse.persistence.internal.helper.DatabaseField; /** * @author Guy Pelletier * @since TOPLink/Java 1.0 */ public class SQLUpdateAllStatement extends SQLModifyStatement { protected HashMap m_updateClauses; protected HashMap databaseFieldsToTableAliases; protected SQLCall selectCallForExist; protected String tableAliasInSelectCallForExist; protected Collection primaryKeyFields; protected boolean shouldExtractWhereClauseFromSelectCallForExist; public void setSelectCallForExist(SQLCall selectCallForExist) { this.selectCallForExist = selectCallForExist; } public SQLCall getSelectCallForExist() { return selectCallForExist; } public void setTableAliasInSelectCallForExist(String tableAliasInSelectCallForExist) { this.tableAliasInSelectCallForExist = tableAliasInSelectCallForExist; } public String getTableAliasInSelectCallForExist() { return tableAliasInSelectCallForExist; } public void setPrimaryKeyFieldsForAutoJoin(Collection primaryKeyFields) { this.primaryKeyFields = primaryKeyFields; } public Collection getPrimaryKeyFieldsForAutoJoin() { return primaryKeyFields; } public void setUpdateClauses(HashMap updateClauses) { m_updateClauses = updateClauses; } public HashMap getUpdateClauses() { return m_updateClauses; } public void setDatabaseFieldsToTableAliases(HashMap databaseFieldsToTableAliases) { this.databaseFieldsToTableAliases = databaseFieldsToTableAliases; } public HashMap getDatabaseFieldsToTableAliases() { return databaseFieldsToTableAliases; } public void setShouldExtractWhereClauseFromSelectCallForExist(boolean shouldExtractWhereClauseFromSelectCallForExist) { this.shouldExtractWhereClauseFromSelectCallForExist = shouldExtractWhereClauseFromSelectCallForExist; } public boolean shouldExtractWhereClauseFromSelectCallForExist() { return shouldExtractWhereClauseFromSelectCallForExist; } /** * Append the string containing the SQL insert string for the given table. */ public DatabaseCall buildCall(AbstractSession session) { SQLCall call = buildSimple(session); if(selectCallForExist == null) { return call; } Writer writer = new CharArrayWriter(100); try { writer.write(call.getSQLString()); if(selectCallForExist != null) { if(shouldExtractWhereClauseFromSelectCallForExist) { // Should get here only in case selectCallForExist doesn't have aliases and // targets the same table as the statement. // Instead of making selectCallForExist part of " WHERE EXIST(" // just extract its where clause. // Example: selectCallForExist.sqlString: // "SELECT PROJ_ID FROM PROJECT WHERE (LEADER_ID IS NULL) writeWhere(writer, selectCallForExist, call); // The result is: // "WHERE (LEADER_ID IS NULL)" } else { writer.write(" WHERE EXISTS("); // EXIST Example: selectCall.sqlString: // "SELECT t0.EMP_ID FROM EMPLOYEE t0, SALARY t1 WHERE (((t0.F_NAME LIKE 'a') AND (t1.SALARY = 0)) AND (t1.EMP_ID = t0.EMP_ID))" writeSelect(writer, selectCallForExist, tableAliasInSelectCallForExist, call, session.getPlatform()); // closing bracket for EXISTS writer.write(")"); } // Bug 301888 - DB2: UpdateAll/DeleteAll using WHERE EXIST fail. // If selectCallForExist has been explicitly set to not use binding then call should be set the same way. if(selectCallForExist.isUsesBindingSet() && !selectCallForExist.usesBinding(session)) { call.setUsesBinding(false); } } call.setSQLString(writer.toString()); } catch (IOException exception) { throw ValidationException.fileError(exception); } return call; } protected SQLCall buildSimple(AbstractSession session) { SQLCall call = new SQLCall(); call.returnNothing(); Writer writer = new CharArrayWriter(100); ExpressionSQLPrinter printer = new ExpressionSQLPrinter(session, getTranslationRow(), call, false, getBuilder()); printer.setWriter(writer); try { // UPDATE // writer.write("UPDATE "); // HINT STRING // if (getHintString() != null) { writer.write(getHintString()); writer.write(" "); } writer.write(getTable().getQualifiedNameDelimited(session.getPlatform())); // SET CLAUSE // writer.write(" SET "); Iterator i = m_updateClauses.keySet().iterator(); boolean commaNeeded = false; while (i.hasNext()) { if (commaNeeded) { writer.write(", "); } DatabaseField field = (DatabaseField)i.next(); Object value = m_updateClauses.get(field); writer.write(field.getNameDelimited(session.getPlatform())); writer.write(" = "); if(value instanceof Expression) { printer.printExpression((Expression)value); } else { // must be SQLCall SQLCall selCall = (SQLCall)value; String tableAlias = (String)getDatabaseFieldsToTableAliases().get(field); // should be SQLCall select writer.write("("); writeSelect(writer, selCall, tableAlias, call, session.getPlatform()); writer.write(")"); } commaNeeded = true; } // WHERE CLAUSE // if (getWhereClause() != null) { writer.write(" WHERE "); printer.printExpression(getWhereClause()); } call.setSQLString(writer.toString()); return call; } catch (IOException exception) { throw ValidationException.fileError(exception); } } protected void writeSelect(Writer writer, SQLCall selectCall, String tableAliasInSelectCall, SQLCall call, DatasourcePlatform platform) throws IOException { String str = selectCall.getSQLString(); writer.write(str); boolean hasWhereClause = str.toUpperCase().indexOf(" WHERE ") >= 0; // Auto join // Example: AND t0.EMP_ID = EMP_ID Iterator it = getPrimaryKeyFieldsForAutoJoin().iterator(); while(it.hasNext()) { if(!hasWhereClause) { // there is no where clause - should print WHERE writer.write(" WHERE "); hasWhereClause = true; } else { writer.write(" AND "); } String fieldName = ((DatabaseField)it.next()).getNameDelimited(platform); if(tableAliasInSelectCall != null) { writer.write(tableAliasInSelectCall); writer.write('.'); } writer.write(fieldName); writer.write(" = "); writer.write(table.getQualifiedNameDelimited(platform)); writer.write('.'); writer.write(fieldName); } call.getParameters().addAll(selectCall.getParameters()); call.getParameterTypes().addAll(selectCall.getParameterTypes()); } protected boolean writeWhere(Writer writer, SQLCall selectCall, SQLCall call) throws IOException { String selectStr = selectCallForExist.getSQLString(); int index = selectStr.toUpperCase().indexOf(" WHERE "); if(index < 0) { // no where clause - nothing to do return false; } // print the where clause String str = selectStr.substring(index); writer.write(str); // add parameters call.getParameters().addAll(selectCall.getParameters()); call.getParameterTypes().addAll(selectCall.getParameterTypes()); return true; } }