code: public <T, S> CallResults call(InputHandler<T> inputHandler, OutputHandler<S> outputHandler, String catalog, String schema, boolean useCache) throws SQLException {
          AssertUtils.assertNotNull(inputHandler, nullException());
          AssertUtils.assertNotNull(outputHandler, nullException());
  
          QueryParameters params = null;
          String procedureName = CallableUtils.getStoredProcedureShortNameFromSql(inputHandler.getQueryString());
          boolean isFunction = CallableUtils.isFunctionCall(inputHandler.getQueryString());
          T input = null;
          S output = null;
          boolean closeStatement = true;
  
          CallResults<T, S> results = new CallResults(procedureName, isFunction);
  
          if (inputHandler instanceof AbstractQueryInputHandler) {
              params = callInner((AbstractQueryInputHandler) inputHandler, outputHandler);
          } else if (inputHandler instanceof AbstractNamedInputHandler) {
              QueryInputHandler queryInput = convertToQueryInputHandler((AbstractNamedInputHandler) inputHandler, catalog, schema, useCache);
  
              params = callInner(queryInput, outputHandler);
          } else {
              throw new IllegalArgumentException();
          }
  
          results.setCallOutput((S) params.getReturn());
  
          params.removeReturn();
  
          if (inputHandler instanceof AbstractQueryInputHandler) {
              input = (T) params;
          } else if (inputHandler instanceof AbstractNamedInputHandler) {
              input = (T) ((AbstractNamedInputHandler) inputHandler).updateInput(params);
          } else {
              throw new IllegalArgumentException();
          }
          results.setCallInput(input);
  
          return results;
      }
docs: {@inheritDoc}