=== modified file 'src/com/goldencode/p2j/persist/OutputTableCopier.java'
--- old/src/com/goldencode/p2j/persist/OutputTableCopier.java	2022-10-06 08:18:44 +0000
+++ new/src/com/goldencode/p2j/persist/OutputTableCopier.java	2022-10-27 09:58:05 +0000
@@ -9,6 +9,7 @@
 ** 002 CA  20190311 A buffer may be active as the source for multiple output table parameters.
 ** 003 CA  20190728 This needs to be processed first, before buffer's are closing their scope.
 ** 004 CA  20221006 Added JMX instrumentation for 'finished'. Refs #6814
+** 005 DDF 20221027 Added additional parameter to differentiate type of copy operation. (refs. #6714)
 */
 /*
 ** This program is free software: you can redistribute it and/or modify
@@ -85,6 +86,9 @@
    
    /** The table parameter where to copy the data. */
    private TableParameter outputParam;
+   
+   /** Used to check if copy should be done using insert or delete-update. */
+   private boolean shouldInsert;
 
    /**
     * Creates a copier for the table.
@@ -93,18 +97,22 @@
     *           A buffer of the table which should be copied.
     * @param    outputParam
     *           The table parameter where to copy the data.
+    * @param    shouldInsert
+    *           {@code true} Copy is done using insert based on select.
+    *           {@code false} Copy is done using delete-update.
     */
-   public OutputTableCopier(TemporaryBuffer srcBuf, TableParameter outputParam)
+   public OutputTableCopier(TemporaryBuffer srcBuf, TableParameter outputParam, boolean shouldInsert)
    {
       this.srcBuf = srcBuf;
       this.outputParam = outputParam;
+      this.shouldInsert = shouldInsert;
    }
 
    /** Copies data in OUTPUT direction.*/
    @Override
    public void finished()
    {
-      COPIER.timer(() -> srcBuf.performOutputCopy(outputParam));
+      COPIER.timer(() -> srcBuf.performOutputCopy(outputParam, shouldInsert));
    }
 
    /** No-op. */
@@ -136,4 +144,4 @@
    {
       return WeightFactor.FIRST;
    }
-}
\ No newline at end of file
+}

=== modified file 'src/com/goldencode/p2j/persist/TemporaryBuffer.java'
--- old/src/com/goldencode/p2j/persist/TemporaryBuffer.java	2022-10-20 00:31:48 +0000
+++ new/src/com/goldencode/p2j/persist/TemporaryBuffer.java	2022-10-27 09:58:15 +0000
@@ -585,6 +585,8 @@
 **                           parameter and bound to another buffer.
 **     OM  20221012          The TriggerTracker are bound to DMO, not to the buffer they are contained into.
 **     OM  20221019          Do not assign new PK for replaced records in copyAllRows().
+*      DDF 20221027          Optimization when copying temp-tables based on multiplexID 
+*                            by using delete-update instead of insert based on select. (refs. #6714)
 */
 
 /*
@@ -2274,7 +2276,14 @@
          }
          dstBuf.outputParameters.add(src);
          
-         OutputTableCopier copier = new OutputTableCopier(dstBuf, src);
+         Object referent = ProcedureManager.thisProcedure().get();
+         boolean isPersistent = ProcedureManager._isPersistent(referent);
+         boolean isExternalBlock = dstBuf.getTxHelper().isExternalBlock();
+         BufferImpl dstBufImpl = (BufferImpl) dstDMO;
+         boolean isAfterTable = dstBufImpl.isAfterBuffer();
+         
+         boolean shouldInsert = (isPersistent || !isExternalBlock) || isAfterTable;
+         OutputTableCopier copier = new OutputTableCopier(dstBuf, src, shouldInsert);
          ProcedureManager.executeOnReturn(copier::finished, copier.weight());
       }
    }
@@ -6375,6 +6384,20 @@
     */
    protected void performOutputCopy(TableParameter outputParameter)
    {
+      performOutputCopy(outputParameter, true);   
+   }
+   
+   /**
+    * Copy output data for the linked table parameter, if any.
+    * 
+    * @param    outputParameter
+    *           The table parameter where to copy the data.
+    * @param    shouldInsert
+    *           If the output copy should be done using an insert based
+    *           on select or a delete-update operation.
+    */
+   protected void performOutputCopy(TableParameter outputParameter, boolean shouldInsert)
+   {
       if (!outputParameters.contains(outputParameter))
       {
          // was already processed (by i.e. scope close)
@@ -6390,13 +6413,40 @@
 
          if (outputParameter.getTable() != null)
          {
-            boolean res = copyAllRows(srcRec,
-                                      tempDMO,
-                                      outputParameter.getTable(),
-                                      outputParameter.isAppend(),
-                                      CopyTableMode.OUTPUT_TABLE_PARAM_MODE);
+            boolean res = false;
+            if (shouldInsert)
+            {
+               res = copyAllRows(srcRec,
+                                 tempDMO,
+                                 outputParameter.getTable(),
+                                 outputParameter.isAppend(),
+                                 CopyTableMode.OUTPUT_TABLE_PARAM_MODE);
+            }
+            else 
+            {
+               TemporaryBuffer targetBuf = (TemporaryBuffer) 
+                                          ((BufferReference) outputParameter.getTable())
+                                          .buffer();
+               int targetMultiplex = targetBuf.getMultiplexID();
+               try
+               {
+                  if (!outputParameter.isAppend())
+                  {
+                     removeRecords(null, null, null, true, targetMultiplex);
+                  }
+                  removeRecords(null, null, null, false, targetMultiplex);
+                  res = true;
+               }
+               catch (PersistenceException e)
+               {
+                  LOG.log(Level.WARNING, "Failed to perform delete-update copy", e);
+               }
+            }
+            
             if (!res)
+            {
                deferCopyError();
+            }
          }
          else
          {
@@ -7282,6 +7332,47 @@
    private void removeRecords(DataModelObject[] extDMOs, String where, Object[] args, boolean forceDelete)
    throws PersistenceException
    {
+      removeRecords(extDMOs, where, args, forceDelete, multiplexID);
+   }
+   
+   /**
+    * Remove or change the multiplex ID for all record rows from the backing table which meet the
+    * specified criteria. Because temp table instances are multiplexed across nested buffer scopes
+    * and across multiple buffers which use the same backing DMO type, the backing table cannot be
+    * dropped until after the last buffer scope referencing the backing table in the current
+    * context has been closed.  This method is invoked for all buffer scope closing events.
+    * This is also the worker method for the {@link #deleteAll()} and 
+    * {@link RecordBuffer#delete(DataModelObject[], String, Object[])} methods.
+    *
+    * @param   extDMOs
+    *          The DMOs for the external (additional) buffers that are accessed in inner
+    *          subselect, or {@code null} in case of a simple {@code where} predicate.
+    * @param   where
+    *          An HQL where clause snippet which defines the restriction
+    *          criteria to apply to the delete.  All references to properties
+    *          in a DMO must be unqualified.  <code>null</code> to delete all
+    *          records whose multiplex IDs match that of this buffer.
+    * @param   args
+    *          Query substitution parameters required by the where clause.
+    *          <code>null</code> if there are no substitutions or no where clause.
+    * @param   forceDelete
+    *          Force the records to be deleted from the table, not just
+    *          marking them with a negative multiplex ID.
+    * @param   targetMultiplexID
+    *          Used to delete records from a buffer and then update the multiplex
+    *          of the source buffer to the targetMultiplexID instead of inserting all the records.
+    *          The default value is the multiplexID.
+    * 
+    * @throws  PersistenceException
+    *          if an error occurs performing the bulk delete operation.
+    */
+   private void removeRecords(DataModelObject[] extDMOs,
+                              String where,
+                              Object[] args,
+                              boolean forceDelete,
+                              int targetMultiplexID)
+   throws PersistenceException
+   {
       Record currentRec = getCurrentRecord();
       
       // after executing this method, the buffer is empty regardless the where predicate matches
@@ -7298,13 +7389,13 @@
       
       if (extDMOs == null || extDMOs.length == 0)
       {
-         ffCache.invalidate(getDmoInfo().getId(), multiplexID);
+         ffCache.invalidate(getDmoInfo().getId(), targetMultiplexID);
       }
       else
       {
          int len = extDMOs.length;
          List<Long> tableIds = new ArrayList<>(len + 1);
-         tableIds.add(FastFindCache.combine(getDmoInfo().getId(), multiplexID));
+         tableIds.add(FastFindCache.combine(getDmoInfo().getId(), targetMultiplexID));
          for (int i = 0; i < len; i++)
          {
             RecordBuffer buffer = ((BufferReference) extDMOs[i]).buffer();
@@ -7321,8 +7412,11 @@
          return;
       }
       
-      // if we are not within a transaction, or this temp-table is not undoable
-      forceDelete = forceDelete || !isUndoable() || !bufferManager.isTransaction();
+      if (targetMultiplexID == multiplexID)
+      {
+         // if we are not within a transaction, or this temp-table is not undoable
+         forceDelete = forceDelete || !isUndoable() || !bufferManager.isTransaction();
+      }
       
       boolean hasWhere = (where != null);
       Persistence persistence = getPersistence();
@@ -7352,7 +7446,16 @@
       buf.append(aliasDot);
       buf.append(MULTIPLEX_FIELD_NAME);
       buf.append(" = ");
-      buf.append(multiplexID);
+      
+      if (forceDelete && targetMultiplexID != multiplexID)
+      {
+         buf.append(targetMultiplexID);
+      }
+      else 
+      {
+         buf.append(multiplexID);
+      }
+      
       String mpidWhere = buf.toString();
       
       HQLExpression query = new HQLExpression();
@@ -7364,10 +7467,17 @@
       else
       {
          query.append("update ");
-         Map<Class<?>, Map<Integer, Integer>> map = local.inUseMPIDs;
-         Map<Integer, Integer> inUse = map.get(getDMOInterface());
-         
-         delMPID = local.getNextMPID(inUse);
+         if (targetMultiplexID == multiplexID)
+         {
+            Map<Class<?>, Map<Integer, Integer>> map = local.inUseMPIDs;
+            Map<Integer, Integer> inUse = map.get(getDMOInterface());
+            
+            delMPID = local.getNextMPID(inUse);
+         }
+         else 
+         {
+            delMPID = targetMultiplexID;
+         }
       }
       
       String table = getTable();
@@ -7410,7 +7520,7 @@
       query.append(mpidWhere);
       if (hasOO)
       {
-         list.append(dmoAlias).append(".").append(MULTIPLEX_FIELD_NAME).append("=").append(multiplexID);
+         list.append(dmoAlias).append(".").append(MULTIPLEX_FIELD_NAME).append("=").append(targetMultiplexID);
       }
       if (hasWhere)
       {
@@ -7529,7 +7639,7 @@
             // execute a simple query to determine if there is any record in this virtual table
             String checkStmt = 
                   "select tt." + Session.PK + " from " + table + " tt " +
-                  "where tt." + MULTIPLEX_FIELD_NAME + " = " + multiplexID + " limit 1";
+                  "where tt." + MULTIPLEX_FIELD_NAME + " = " + targetMultiplexID + " limit 1";
             Long id = persistence.getSingleSQLResult(checkStmt, null);
             full = (id == null);
          }
@@ -7546,7 +7656,19 @@
       // if the virtual table is now empty, mark it as such
       if (full)
       {
-         local.emptyTableFlags.put(multiplexID, Boolean.TRUE);
+         if (forceDelete)
+         {
+            local.emptyTableFlags.put(targetMultiplexID, Boolean.TRUE);
+         }
+         else 
+         {
+            local.emptyTableFlags.put(multiplexID, Boolean.TRUE);
+            if (targetMultiplexID != multiplexID)
+            {
+               local.emptyTableFlags.put(targetMultiplexID, Boolean.FALSE);
+            }
+         }
+         
       }
    }
    

