/**
  * Match input parameter values with the parameters declared to be used in the call.
  *
  * @param inParameters the input values
  * @return a Map containing the matched parameter names with the value taken from the input
  */
 public Map<String, ?> matchInParameterValuesWithCallParameters(Map<String, ?> inParameters) {
   if (!this.metaDataProvider.isProcedureColumnMetaDataUsed()) {
     return inParameters;
   }
   Map<String, String> callParameterNames =
       new HashMap<String, String>(this.callParameters.size());
   for (SqlParameter parameter : this.callParameters) {
     if (parameter.isInputValueProvided()) {
       String parameterName = parameter.getName();
       String parameterNameToMatch = this.metaDataProvider.parameterNameToUse(parameterName);
       if (parameterNameToMatch != null) {
         callParameterNames.put(parameterNameToMatch.toLowerCase(), parameterName);
       }
     }
   }
   Map<String, Object> matchedParameters = new HashMap<String, Object>(inParameters.size());
   for (String parameterName : inParameters.keySet()) {
     String parameterNameToMatch = this.metaDataProvider.parameterNameToUse(parameterName);
     String callParameterName = callParameterNames.get(parameterNameToMatch.toLowerCase());
     if (callParameterName == null) {
       if (logger.isDebugEnabled()) {
         Object value = inParameters.get(parameterName);
         if (value instanceof SqlParameterValue) {
           value = ((SqlParameterValue) value).getValue();
         }
         if (value != null) {
           logger.debug(
               "Unable to locate the corresponding IN or IN-OUT parameter for \""
                   + parameterName
                   + "\" in the parameters used: "
                   + callParameterNames.keySet());
         }
       }
     } else {
       matchedParameters.put(callParameterName, inParameters.get(parameterName));
     }
   }
   if (matchedParameters.size() < callParameterNames.size()) {
     for (String parameterName : callParameterNames.keySet()) {
       String parameterNameToMatch = this.metaDataProvider.parameterNameToUse(parameterName);
       String callParameterName = callParameterNames.get(parameterNameToMatch.toLowerCase());
       if (!matchedParameters.containsKey(callParameterName)) {
         logger.warn(
             "Unable to locate the corresponding parameter value for '"
                 + parameterName
                 + "' within the parameter values provided: "
                 + inParameters.keySet());
       }
     }
   }
   if (logger.isDebugEnabled()) {
     logger.debug("Matching " + inParameters.keySet() + " with " + callParameterNames.values());
     logger.debug("Found match for " + matchedParameters.keySet());
   }
   return matchedParameters;
 }
 public Map<String, ?> matchInParameterValuesWithCallParameters(Object[] parameterValues) {
   Map<String, Object> matchedParameters = new HashMap<String, Object>(parameterValues.length);
   int i = 0;
   for (SqlParameter parameter : this.callParameters) {
     if (parameter.isInputValueProvided()) {
       String parameterName = parameter.getName();
       matchedParameters.put(parameterName, parameterValues[i++]);
     }
   }
   return matchedParameters;
 }
  /**
   * Build the call string based on configuration and metadata information.
   *
   * @return the call string to be used
   */
  public String createCallString() {
    String callString;
    int parameterCount = 0;
    String catalogNameToUse;
    String schemaNameToUse;

    // For Oracle where catalogs are not supported we need to reverse the schema name
    // and the catalog name since the cataog is used for the package name
    if (this.metaDataProvider.isSupportsSchemasInProcedureCalls()
        && !this.metaDataProvider.isSupportsCatalogsInProcedureCalls()) {
      schemaNameToUse = this.metaDataProvider.catalogNameToUse(getCatalogName());
      catalogNameToUse = this.metaDataProvider.schemaNameToUse(getSchemaName());
    } else {
      catalogNameToUse = this.metaDataProvider.catalogNameToUse(getCatalogName());
      schemaNameToUse = this.metaDataProvider.schemaNameToUse(getSchemaName());
    }
    String procedureNameToUse = this.metaDataProvider.procedureNameToUse(getProcedureName());
    if (isFunction() || isReturnValueRequired()) {
      callString =
          "{? = call "
              + (StringUtils.hasLength(catalogNameToUse) ? catalogNameToUse + "." : "")
              + (StringUtils.hasLength(schemaNameToUse) ? schemaNameToUse + "." : "")
              + procedureNameToUse
              + "(";
      parameterCount = -1;
    } else {
      callString =
          "{call "
              + (StringUtils.hasLength(catalogNameToUse) ? catalogNameToUse + "." : "")
              + (StringUtils.hasLength(schemaNameToUse) ? schemaNameToUse + "." : "")
              + procedureNameToUse
              + "(";
    }
    for (SqlParameter parameter : this.callParameters) {
      if (!(parameter.isResultsParameter())) {
        if (parameterCount > 0) {
          callString += ", ";
        }
        if (parameterCount >= 0) {
          callString += createParameterBinding(parameter);
        }
        parameterCount++;
      }
    }
    callString += ")}";

    return callString;
  }
 /**
  * Build the parameter binding fragment.
  *
  * @param parameter call parameter
  * @return parameter binding fragment
  * @since 4.2
  */
 protected String createParameterBinding(SqlParameter parameter) {
   if (isNamedBinding()) {
     return parameter.getName() + " => ?";
   } else {
     return "?";
   }
 }
 /**
  * Add a declared parameter to teh list of parameters for the call
  *
  * @param parameter the {@link SqlParameter} to add
  */
 public void addDeclaredParameter(SqlParameter parameter) {
   this.declaredParameters.add(parameter);
   if (logger.isDebugEnabled()) {
     logger.debug(
         "Added declared parameter for [" + getProcedureName() + "]: " + parameter.getName());
   }
 }
Ejemplo n.º 6
0
  /**
   * Overridden method to configure the CallableStatementCreatorFactory based on our declared
   * parameters.
   *
   * @see RdbmsOperation#compileInternal()
   */
  @Override
  protected final void compileInternal() {
    if (isSqlReadyForUse()) {
      this.callString = getSql();
    } else {
      List<SqlParameter> parameters = getDeclaredParameters();
      int parameterCount = 0;
      if (isFunction()) {
        this.callString = "{? = call " + getSql() + "(";
        parameterCount = -1;
      } else {
        this.callString = "{call " + getSql() + "(";
      }
      for (SqlParameter parameter : parameters) {
        if (!(parameter.isResultsParameter())) {
          if (parameterCount > 0) {
            this.callString += ", ";
          }
          if (parameterCount >= 0) {
            this.callString += "?";
          }
          parameterCount++;
        }
      }
      this.callString += ")}";
    }
    if (logger.isDebugEnabled()) {
      logger.debug("Compiled stored procedure. Call string is [" + getCallString() + "]");
    }

    this.callableStatementFactory =
        new CallableStatementCreatorFactory(getCallString(), getDeclaredParameters());
    this.callableStatementFactory.setResultSetType(getResultSetType());
    this.callableStatementFactory.setUpdatableResults(isUpdatableResults());
    this.callableStatementFactory.setNativeJdbcExtractor(
        getJdbcTemplate().getNativeJdbcExtractor());

    onCompileInternal();
  }
 /** Mathod to perform the actual call processing */
 private Map<String, Object> executeCallInternal(Map params) {
   CallableStatementCreator csc =
       getCallableStatementFactory().newCallableStatementCreator(params);
   if (logger.isDebugEnabled()) {
     logger.debug(
         "The following parameters are used for call " + getCallString() + " with: " + params);
     int i = 1;
     for (SqlParameter p : getCallParameters()) {
       logger.debug(
           i++
               + ": "
               + p.getName()
               + " SQL Type "
               + p.getSqlType()
               + " Type Name "
               + p.getTypeName()
               + " "
               + p.getClass().getName());
     }
   }
   Map<String, Object> result = getJdbcTemplate().call(csc, getCallParameters());
   return result;
 }
  /**
   * Match input parameter values with the parameters declared to be used in the call.
   *
   * @param parameterSource the input values
   * @return a Map containing the matched parameter names with the value taken from the input
   */
  public Map<String, Object> matchInParameterValuesWithCallParameters(
      SqlParameterSource parameterSource) {
    // For parameter source lookups we need to provide case-insensitive lookup support
    // since the database metadata is not necessarily providing case sensitive parameter names.
    Map<String, String> caseInsensitiveParameterNames =
        SqlParameterSourceUtils.extractCaseInsensitiveParameterNames(parameterSource);

    Map<String, String> callParameterNames =
        new HashMap<String, String>(this.callParameters.size());
    Map<String, Object> matchedParameters = new HashMap<String, Object>(this.callParameters.size());
    for (SqlParameter parameter : this.callParameters) {
      if (parameter.isInputValueProvided()) {
        String parameterName = parameter.getName();
        String parameterNameToMatch = this.metaDataProvider.parameterNameToUse(parameterName);
        if (parameterNameToMatch != null) {
          callParameterNames.put(parameterNameToMatch.toLowerCase(), parameterName);
        }
        if (parameterName != null) {
          if (parameterSource.hasValue(parameterName)) {
            matchedParameters.put(
                parameterName,
                SqlParameterSourceUtils.getTypedValue(parameterSource, parameterName));
          } else {
            String lowerCaseName = parameterName.toLowerCase();
            if (parameterSource.hasValue(lowerCaseName)) {
              matchedParameters.put(
                  parameterName,
                  SqlParameterSourceUtils.getTypedValue(parameterSource, lowerCaseName));
            } else {
              String englishLowerCaseName = parameterName.toLowerCase(Locale.ENGLISH);
              if (parameterSource.hasValue(englishLowerCaseName)) {
                matchedParameters.put(
                    parameterName,
                    SqlParameterSourceUtils.getTypedValue(parameterSource, englishLowerCaseName));
              } else {
                String propertyName = JdbcUtils.convertUnderscoreNameToPropertyName(parameterName);
                if (parameterSource.hasValue(propertyName)) {
                  matchedParameters.put(
                      parameterName,
                      SqlParameterSourceUtils.getTypedValue(parameterSource, propertyName));
                } else {
                  if (caseInsensitiveParameterNames.containsKey(lowerCaseName)) {
                    String sourceName = caseInsensitiveParameterNames.get(lowerCaseName);
                    matchedParameters.put(
                        parameterName,
                        SqlParameterSourceUtils.getTypedValue(parameterSource, sourceName));
                  } else {
                    logger.warn(
                        "Unable to locate the corresponding parameter value for '"
                            + parameterName
                            + "' within the parameter values provided: "
                            + caseInsensitiveParameterNames.values());
                  }
                }
              }
            }
          }
        }
      }
    }

    if (logger.isDebugEnabled()) {
      logger.debug(
          "Matching "
              + caseInsensitiveParameterNames.values()
              + " with "
              + callParameterNames.values());
      logger.debug("Found match for " + matchedParameters.keySet());
    }
    return matchedParameters;
  }
  /**
   * Reconcile the provided parameters with available metadata and add new ones where appropriate.
   */
  protected List<SqlParameter> reconcileParameters(List<SqlParameter> parameters) {
    final List<SqlParameter> declaredReturnParams = new ArrayList<SqlParameter>();
    final Map<String, SqlParameter> declaredParams = new LinkedHashMap<String, SqlParameter>();
    boolean returnDeclared = false;
    List<String> outParamNames = new ArrayList<String>();
    List<String> metaDataParamNames = new ArrayList<String>();

    // Get the names of the meta data parameters
    for (CallParameterMetaData meta : this.metaDataProvider.getCallParameterMetaData()) {
      if (meta.getParameterType() != DatabaseMetaData.procedureColumnReturn) {
        metaDataParamNames.add(meta.getParameterName().toLowerCase());
      }
    }

    // Separate implicit return parameters from explicit parameters...
    for (SqlParameter param : parameters) {
      if (param.isResultsParameter()) {
        declaredReturnParams.add(param);
      } else {
        String paramName = param.getName();
        if (paramName == null) {
          throw new IllegalArgumentException(
              "Anonymous parameters not supported for calls - "
                  + "please specify a name for the parameter of SQL type "
                  + param.getSqlType());
        }
        String paramNameToMatch = this.metaDataProvider.parameterNameToUse(paramName).toLowerCase();
        declaredParams.put(paramNameToMatch, param);
        if (param instanceof SqlOutParameter) {
          outParamNames.add(paramName);
          if (isFunction() && !metaDataParamNames.contains(paramNameToMatch)) {
            if (!returnDeclared) {
              if (logger.isDebugEnabled()) {
                logger.debug(
                    "Using declared out parameter '" + paramName + "' for function return value");
              }
              setFunctionReturnName(paramName);
              returnDeclared = true;
            }
          }
        }
      }
    }
    setOutParameterNames(outParamNames);

    List<SqlParameter> workParams = new ArrayList<SqlParameter>();
    workParams.addAll(declaredReturnParams);

    if (!this.metaDataProvider.isProcedureColumnMetaDataUsed()) {
      workParams.addAll(declaredParams.values());
      return workParams;
    }

    Map<String, String> limitedInParamNamesMap =
        new HashMap<String, String>(this.limitedInParameterNames.size());
    for (String limitedParamName : this.limitedInParameterNames) {
      limitedInParamNamesMap.put(
          this.metaDataProvider.parameterNameToUse(limitedParamName).toLowerCase(),
          limitedParamName);
    }

    for (CallParameterMetaData meta : this.metaDataProvider.getCallParameterMetaData()) {
      String paramNameToCheck = null;
      if (meta.getParameterName() != null) {
        paramNameToCheck =
            this.metaDataProvider.parameterNameToUse(meta.getParameterName()).toLowerCase();
      }
      String paramNameToUse = this.metaDataProvider.parameterNameToUse(meta.getParameterName());
      if (declaredParams.containsKey(paramNameToCheck)
          || (meta.getParameterType() == DatabaseMetaData.procedureColumnReturn
              && returnDeclared)) {
        SqlParameter param;
        if (meta.getParameterType() == DatabaseMetaData.procedureColumnReturn) {
          param = declaredParams.get(getFunctionReturnName());
          if (param == null && getOutParameterNames().size() > 0) {
            param = declaredParams.get(getOutParameterNames().get(0).toLowerCase());
          }
          if (param == null) {
            throw new InvalidDataAccessApiUsageException(
                "Unable to locate declared parameter for function return value - "
                    + " add a SqlOutParameter with name '"
                    + getFunctionReturnName()
                    + "'");
          } else {
            setFunctionReturnName(param.getName());
          }
        } else {
          param = declaredParams.get(paramNameToCheck);
        }
        if (param != null) {
          workParams.add(param);
          if (logger.isDebugEnabled()) {
            logger.debug(
                "Using declared parameter for '"
                    + (paramNameToUse != null ? paramNameToUse : getFunctionReturnName())
                    + "'");
          }
        }
      } else {
        if (meta.getParameterType() == DatabaseMetaData.procedureColumnReturn) {
          if (!isFunction()
              && !isReturnValueRequired()
              && this.metaDataProvider.byPassReturnParameter(meta.getParameterName())) {
            if (logger.isDebugEnabled()) {
              logger.debug(
                  "Bypassing metadata return parameter for '" + meta.getParameterName() + "'");
            }
          } else {
            String returnNameToUse =
                (StringUtils.hasLength(meta.getParameterName())
                    ? paramNameToUse
                    : getFunctionReturnName());
            workParams.add(this.metaDataProvider.createDefaultOutParameter(returnNameToUse, meta));
            if (isFunction()) {
              setFunctionReturnName(returnNameToUse);
              outParamNames.add(returnNameToUse);
            }
            if (logger.isDebugEnabled()) {
              logger.debug("Added metadata return parameter for '" + returnNameToUse + "'");
            }
          }
        } else {
          if (meta.getParameterType() == DatabaseMetaData.procedureColumnOut) {
            workParams.add(this.metaDataProvider.createDefaultOutParameter(paramNameToUse, meta));
            outParamNames.add(paramNameToUse);
            if (logger.isDebugEnabled()) {
              logger.debug("Added metadata out parameter for '" + paramNameToUse + "'");
            }
          } else if (meta.getParameterType() == DatabaseMetaData.procedureColumnInOut) {
            workParams.add(this.metaDataProvider.createDefaultInOutParameter(paramNameToUse, meta));
            outParamNames.add(paramNameToUse);
            if (logger.isDebugEnabled()) {
              logger.debug("Added metadata in out parameter for '" + paramNameToUse + "'");
            }
          } else {
            if (this.limitedInParameterNames.isEmpty()
                || limitedInParamNamesMap.containsKey(paramNameToUse.toLowerCase())) {
              workParams.add(this.metaDataProvider.createDefaultInParameter(paramNameToUse, meta));
              if (logger.isDebugEnabled()) {
                logger.debug("Added metadata in parameter for '" + paramNameToUse + "'");
              }
            } else {
              if (logger.isDebugEnabled()) {
                logger.debug(
                    "Limited set of parameters "
                        + limitedInParamNamesMap.keySet()
                        + " skipped parameter for '"
                        + paramNameToUse
                        + "'");
              }
            }
          }
        }
      }
    }

    return workParams;
  }
  @SuppressWarnings("unchecked")
  @Test
  public void testSqlParametersAreSet() throws Exception {
    setUp("basicStoredProcOutboundChannelAdapterTest.xml", getClass());

    DirectFieldAccessor accessor = new DirectFieldAccessor(this.consumer);
    Object handler = accessor.getPropertyValue("handler");
    accessor = new DirectFieldAccessor(handler);

    Object executor = accessor.getPropertyValue("executor");
    DirectFieldAccessor executorAccessor = new DirectFieldAccessor(executor);

    Object sqlParameters = executorAccessor.getPropertyValue("sqlParameters");

    assertNotNull(sqlParameters);
    assertTrue(sqlParameters instanceof List);

    List<SqlParameter> sqlParametersAsList = (List<SqlParameter>) sqlParameters;

    assertTrue(sqlParametersAsList.size() == 4);

    SqlParameter parameter1 = sqlParametersAsList.get(0);
    SqlParameter parameter2 = sqlParametersAsList.get(1);
    SqlParameter parameter3 = sqlParametersAsList.get(2);
    SqlParameter parameter4 = sqlParametersAsList.get(3);

    assertEquals("username", parameter1.getName());
    assertEquals("password", parameter2.getName());
    assertEquals("age", parameter3.getName());
    assertEquals("description", parameter4.getName());

    assertNull("Expect that the scale is null.", parameter1.getScale());
    assertNull("Expect that the scale is null.", parameter2.getScale());
    assertEquals("Expect that the scale is 5.", Integer.valueOf(5), parameter3.getScale());
    assertNull("Expect that the scale is null.", parameter4.getScale());

    assertEquals("SqlType is ", Types.VARCHAR, parameter1.getSqlType());
    assertEquals("SqlType is ", Types.VARCHAR, parameter2.getSqlType());
    assertEquals("SqlType is ", Types.INTEGER, parameter3.getSqlType());
    assertEquals("SqlType is ", Types.VARCHAR, parameter4.getSqlType());

    assertTrue(parameter1 instanceof SqlParameter);
    assertTrue(parameter2 instanceof SqlOutParameter);
    assertTrue(parameter3 instanceof SqlInOutParameter);
    assertTrue(parameter4 instanceof SqlParameter);
  }