@Override
  public void prepare(CallableStatement statement, int startIndex) throws SQLException {
    if (mode == ParameterMode.REF_CURSOR) {
      throw new NotYetImplementedException("Support for REF_CURSOR parameters not yet supported");
    }

    this.startIndex = startIndex;
    if (mode == ParameterMode.IN || mode == ParameterMode.INOUT || mode == ParameterMode.OUT) {
      if (mode == ParameterMode.INOUT || mode == ParameterMode.OUT) {
        if (sqlTypes.length > 1) {
          if (ProcedureParameterExtractionAware.class.isInstance(hibernateType)
              && ((ProcedureParameterExtractionAware) hibernateType).canDoExtraction()) {
            // the type can handle multi-param extraction...
          } else {
            // it cannot...
            throw new UnsupportedOperationException(
                "Type [" + hibernateType + "] does support multi-parameter value extraction");
          }
        }
        for (int i = 0; i < sqlTypes.length; i++) {
          statement.registerOutParameter(startIndex + i, sqlTypes[i]);
        }
      }

      if (mode == ParameterMode.INOUT || mode == ParameterMode.IN) {
        if (bind == null || bind.getValue() == null) {
          // the user did not bind a value to the parameter being processed.  That might be ok *if*
          // the
          // procedure as defined in the database defines a default value for that parameter.
          // Unfortunately there is not a way to reliably know through JDBC metadata whether a
          // procedure
          // parameter defines a default value.  So we simply allow the procedure execution to
          // happen
          // assuming that the database will complain appropriately if not setting the given
          // parameter
          // bind value is an error.
          log.debugf(
              "Stored procedure [%s] IN/INOUT parameter [%s] not bound; assuming procedure defines default value",
              procedureCall.getProcedureName(), this);
        } else {
          final Type typeToUse;
          if (bind.getExplicitTemporalType() != null
              && bind.getExplicitTemporalType() == TemporalType.TIMESTAMP) {
            typeToUse = hibernateType;
          } else if (bind.getExplicitTemporalType() != null
              && bind.getExplicitTemporalType() == TemporalType.DATE) {
            typeToUse = DateType.INSTANCE;
          } else {
            typeToUse = hibernateType;
          }
          typeToUse.nullSafeSet(statement, bind.getValue(), startIndex, session());
        }
      }
    } else {
      // we have a REF_CURSOR type param
      if (procedureCall.getParameterStrategy() == ParameterStrategy.NAMED) {
        session()
            .getFactory()
            .getServiceRegistry()
            .getService(RefCursorSupport.class)
            .registerRefCursorParameter(statement, getName());
      } else {
        session()
            .getFactory()
            .getServiceRegistry()
            .getService(RefCursorSupport.class)
            .registerRefCursorParameter(statement, getPosition());
      }
    }
  }
 protected void bindParameters(SessionImplementor session, PreparedStatement ps, Object entity)
     throws SQLException {
   Object uniqueKeyValue = persister.getPropertyValue(entity, uniqueKeyPropertyName);
   uniqueKeyType.nullSafeSet(ps, uniqueKeyValue, 1, session);
 }