/**
   * The caller will have pushed a DataValueFactory and value of that can be converted to the
   * correct type, e.g. int for a SQL INTEGER.
   *
   * <p>Thus upon entry the stack looks like: ...,dvf,value
   *
   * <p>If field is not null then it is used as the holder of the generated DataValueDescriptor to
   * avoid object creations on multiple passes through this code. The field may contain null or a
   * valid value.
   *
   * <p>This method then sets up to call the required method on DataValueFactory using the
   * dataValueMethodName(). The value left on the stack will be a DataValueDescriptor of the correct
   * type:
   *
   * <p>If the field contained a valid value then generated code will return that value rather than
   * a newly created object. If field was not-null then the generated code will set the value of
   * field to be the return from the DataValueFactory method call. Thus if the field was empty (set
   * to null) when this code is executed it will contain the newly generated value, otherwise it
   * will be reset to the same value.
   *
   * <p>...,dvd
   *
   * @see TypeCompiler#generateDataValue(MethodBuilder, int, LocalField)
   */
  public void generateDataValue(MethodBuilder mb, int collationType, LocalField field) {

    String interfaceName = interfaceName();

    // push the second argument

    /* If fieldName is null, then there is no
     * reusable wrapper (null), else we
     * reuse the field.
     */
    if (field == null) {
      mb.pushNull(interfaceName);
    } else {
      mb.getField(field);
    }

    int argCount;
    if (pushCollationForDataValue(collationType)) {
      mb.push(collationType);
      argCount = 3;
    } else argCount = 2;

    mb.callMethod(
        VMOpcode.INVOKEINTERFACE, (String) null, dataValueMethodName(), interfaceName, argCount);

    if (field != null) {
      /* Store the result of the method call in the field,
       * so we can re-use the wrapper.
       */
      mb.putField(field);
    }
  }
  /**
   * The caller will have pushed a DataValueFactory and a null or a value of the correct type
   * (interfaceName()). Thus upon entry the stack looks like on of: ...,dvf,ref ...,dvf,null
   *
   * <p>This method then sets up to call the required method on DataValueFactory using the
   * nullMethodName(). The value left on the stack will be a DataValueDescriptor of the correct
   * type:
   *
   * <p>...,dvd
   *
   * @see TypeCompiler#generateNull(MethodBuilder, int)
   */
  public void generateNull(MethodBuilder mb, int collationType) {
    int argCount;
    if (pushCollationForDataValue(collationType)) {
      mb.push(collationType);
      argCount = 2;
    } else argCount = 1;

    mb.callMethod(
        VMOpcode.INVOKEINTERFACE, (String) null, nullMethodName(), interfaceName(), argCount);
  }
  public void generateDataValue(MethodBuilder mb, int collationType, LocalField field) {
    if (!JVMInfo.J2ME && getTypeId().isDecimalTypeId()) {
      // cast the value to a Number (from BigDecimal) for method resolution
      // For J2ME there is no implementation of Number for DECIMAL
      // so values are handled as thier original type, which is just
      // a String for DECIMAL constants from the parser.
      mb.upCast("java.lang.Number");
    }

    super.generateDataValue(mb, collationType, field);
  }
  /**
   * Do code generation for this conversion of a value from the Java to the SQL domain.
   *
   * @param acb The ExpressionClassBuilder for the class we're generating
   * @param mb the method the expression will go into
   * @exception StandardException Thrown on error
   */
  public void generateExpression(ExpressionClassBuilder acb, MethodBuilder mb)
      throws StandardException {
    TypeId resultType;
    String resultTypeName;

    /*
     ** Tell the Java node that it's value is being returned to the
     ** SQL domain.  This way, it knows whether the checking for a null
     ** receiver is to be done at the Java level or the SQL level.
     */
    javaNode.returnValueToSQLDomain();

    /* Generate the receiver, if any. */
    boolean hasReceiver = javaNode.generateReceiver(acb, mb);

    /*
     ** If the java expression has a receiver, we want to check whether
     ** it's null before evaluating the whole expression (to avoid
     ** a NullPointerException.
     */
    if (hasReceiver) {
      /*
       ** There is a receiver.  Generate a null SQL value to return
       ** in case the receiver is null.  First, create a field to hold
       ** the null SQL value.
       */
      String nullValueClass = getTypeCompiler().interfaceName();
      LocalField nullValueField = acb.newFieldDeclaration(Modifier.PRIVATE, nullValueClass);
      /*
       ** There is a receiver.  Generate the following to test
       ** for null:
       **
       **		(receiverExpression == null) ?
       */

      mb.conditionalIfNull();
      mb.getField(nullValueField);
      acb.generateNullWithExpress(mb, getTypeCompiler(), getTypeServices().getCollationType());

      /*
       ** We have now generated the expression to test, and the
       ** "true" side of the ?: operator.  Finish the "true" side
       ** so we can generate the "false" side.
       */
      mb.startElseCode();
    }

    resultType = getTypeId();
    TypeCompiler tc = getTypeCompiler();

    resultTypeName = tc.interfaceName();

    /* Allocate an object for re-use to hold the result of the conversion */
    LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, resultTypeName);

    /* Generate the expression for the Java value under us */
    javaNode.generateExpression(acb, mb);

    /* Generate the SQL value, which is always nullable */
    acb.generateDataValue(mb, tc, getTypeServices().getCollationType(), field);

    /*
     ** If there was a receiver, the return value will be the result
     ** of the ?: operator.
     */
    if (hasReceiver) {
      mb.completeConditional();
    }
  }