docs: @Override
      protected SQLException closeWrapper(boolean closeWrapperOnly) 
      {
          final boolean isTraceOn = TraceComponent.isAnyTracingEnabled(); 
  
          SQLException sqlX = null;
  
          // Indicate the statement is closed by setting the parent object's statement to
          // null.  This will allow us to be garbage collected.
  
          try // Connection wrapper can close at any time.
          {
              parentWrapper.childWrappers.remove(this);
          } catch (RuntimeException runtimeX) {
              // No FFDC code needed; parent wrapper might be closed.
              if (parentWrapper.state != State.CLOSED)
                  throw runtimeX;
          }
  
          com.ibm.ws.rsadapter.impl.WSRdbManagedConnectionImpl mc;
  
          // A null key means statement caching is disabled. Do not cache. Close instead.
          // Also don't cache if the poolability hint is FALSE.   
          if (key == null || !poolabilityHint)
              try 
              {
                  if (isTraceOn && tc.isDebugEnabled())
                      Tr.debug(this, tc, key == null ? 
                      "statement caching is disabled" : 
                      "statement is not poolable"); 
  
                  pstmtImpl.close();
              } catch (SQLException closeX) {
                  FFDCFilter.processException(closeX,
                                              getClass().getName() + ".closeWrapper", "264", this);
  
                  Tr.warning(tc, "ERR_CLOSING_OBJECT", pstmtImpl, closeX);
                  sqlX = closeX;
              }
  
          // Do not cache unless we are associated with a ManagedConnection. 
          else if ((mc = ((WSJdbcConnection) parentWrapper).managedConn) == null)
              try {
                  if (isTraceOn && tc.isDebugEnabled())
                      Tr.debug(this, tc, 
                               "Not associated with a ManagedConnection. Statement cannot be cached.");
  
                  pstmtImpl.close();
              } catch (SQLException closeX) {
                  FFDCFilter.processException(closeX,
                                              getClass().getName() + ".closeWrapper", "281", this);
  
                  Tr.warning(tc, "ERR_CLOSING_OBJECT", pstmtImpl, closeX);
                  sqlX = closeX;
              }
  
          // Attempt to cache the statement.
          else
              try {
                  if (!pstmtImpl.getMoreResults() && (mcf.getHelper().getUpdateCount(this) == -1)) { 
                      // Reset any statement properties that have changed. 
                      if (haveStatementPropertiesChanged) {
                          if (isTraceOn && tc.isDebugEnabled())
                              Tr.debug(this, tc, "Cleaning up Statement"); 
                          mcf.getHelper().doStatementCleanup(pstmtImpl);
                          haveStatementPropertiesChanged = false;
                      }
  
                      // Clear statement parameters before caching to release memory 
                      pstmtImpl.clearParameters(); 
  
                      // Batch parameters must be cleared before putting the statement in the cache
                      // because this is the only time information is available regarding whether the
                      // clearBatch is needed. There is no need to reset the 'hasBatchParameters' flag
                      // because statement wrappers are not reusable.
  
                      if (hasBatchParameters) {
                          if (isTraceOn && tc.isDebugEnabled())
                              Tr.debug(this, tc, "Clearing batch parameters"); 
                          pstmtImpl.clearBatch();
                      }
  
                      // Return the statement to the cache.
                      if (tc.isDebugEnabled())
                          Tr.debug(this, tc, "Attempt to cache statement");
                      mc.cacheStatement(pstmtImpl, key);
                  } else {
                      if (tc.isDebugEnabled())
                          Tr.debug(this, tc, "Cannot cache statement as there are unprocessed results");
                      pstmtImpl.close();
                  }
  
              } catch (SQLException cleanupX) {
                  if (!mc.isAborted()) {
                      FFDCFilter.processException(cleanupX, getClass().getName() + ".closeWrapper", "310", this);
                      sqlX = cleanupX;
                  }
  
                  try {
                      pstmtImpl.close();
                  } catch (SQLException closeX) {
                      FFDCFilter.processException(closeX,
                                                  getClass().getName() + ".closeWrapper", "321", this);
  
                      Tr.warning(tc, "ERR_CLOSING_OBJECT", pstmtImpl, closeX);
                  }
              }
  
          stmtImpl = null;
          pstmtImpl = null;
          key = null;
          sql = null; 
  
          return sqlX == null ? null : WSJdbcUtil.mapException(this, sqlX); 
      }