Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4711736

idlj generated stubs incorrectly select default union discriminators

XMLWordPrintable

    • x86
    • windows_2000

      or into the 2 parametered version of the method:

      value.decimalValues (_dis0, _decimalValues);
      (Review ID: 158875)
      ======================================================================


      Name: nt126004 Date: 07/08/2002


      FULL PRODUCT VERSION :
      java version "1.3.1_04"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1_04-b02)
      Java HotSpot(TM) Client VM (build 1.3.1_04-b02, mixed mode)

      FULL OPERATING SYSTEM VERSION : Microsoft Windows 2000
      [Version 5.00.2195]


      A DESCRIPTION OF THE PROBLEM :
      I believe I have spotted a subtle bug in the idlj compiler
      to do with discriminators in unions. I encountered this
      problem using JDK1.3 but I have produced the same result
      using the latest 1.4.1 Beta.

      I am compiling three IDL files from Sybase's EAServer
      product: TabularResults.idl, MJD.idl and BCD.idl.

      As I understand it, the union discriminator is not being
      set correctly when the unioned 'Data' object is being read
      (rebuilt) on the client side. I have drilled down into the
      stub code and the problem seems to be the line marked
      *HERE* in the following stub:

      TabularResults.Data read(...)
      {
        TabularResults.Data value = new TabularResults.Data ();
        int _dis0 = (int)0;
        _dis0 = istream.read_long ();
        switch (_dis0)
        {
          ...
          case TabularResults.TYPE_BIGINT.value:
          case TabularResults.TYPE_DECIMAL.value:
          case TabularResults.TYPE_NUMERIC.value:

          BCD.Decimal _decimalValues[] = null;
          _decimalValues = TabularResults.DecimalSeqHelper.read
      (istream);
          value.decimalValues (_decimalValues); -- *HERE*

          break;
          ...
        }
      }

      As I understand it the code switches on the discriminator
      to figure out what type of unioned object should be built.
      What I believe should be happening is that the line I have
      marked should be passing in the discriminator like this:

         value.decimalValues (_dis0, _decimalValues); -- *HERE*

      Yes there are two versions of this method and the first one
      just sets a default discriminator value. Here they are:

      public void decimalValues (BCD.Decimal[] value)
      {
        __discriminator = TabularResults.TYPE_BIGINT.value;
        ___decimalValues = value;
        __uninitialized = false;
      }

      public void decimalValues (int discriminator, BCD.Decimal[]
      value)
      {
        verifydecimalValues (discriminator);
        __discriminator = discriminator;
        ___decimalValues = value;
        __uninitialized = false;
      }

      As I've said, I reckon it should be calling the second one.

      The interesting part is that if I compile the same IDL file
      using the Sybase tools it does create stubs that call the
      2nd version. Here's the code that is created in this case:

      case (int)-5:
      case (int)3:
      case (int)2:
      {
        value.decimalValues(_switch,
      TabularResults.DecimalSeqHelper.read(_input));
        break;
      }

      Do you think that I am on to something here, or is there is
      something that I am overlooking?

      Thanks for your time,
        Paul.

      -- IDL Source Files are below here --

      ------------------
      TabularResutls.idl
      ------------------

      #include "BCD.idl"
      #include "MJD.idl"

      /*
       * This module defines CORBA IDL constants and types for
      dynamic result
       * set handling, with the intention of supporting easy
      conversion from
       * and to java.sql.ResultSet (or jdbc.sql.ResultSet for JDK
      1.0.2).
       *
       * <p>No interface types are defined for result set
      handling.
       * When an operation returns a result set, the entire
      result set
       * must be transmitted from server to client before the
      client can begin
       * processing the results.
       *
       * <p>This approach has the potential to be much more
      efficient in a wide-area
       * network environment than the use of interface types,
      which would result in a
       * large number of small requests from client to server to
      fetch an entire
       * result set. It is also preferable to streaming the
      result set into an
       * octet sequence, since the IDL language mappings for the
      <code>ResultSet</code>
       * type allow for convenient manipulation of result set
      data and meta-data.
       *
       * <p>If a client requires the ability to process some
      results before all the
       * results have been transmitted, the result set can be
      explicitly broken
       * into batches by the server programmer using an IDL
      interface such as:
       * <pre>
       * interface SampleInterface
       * {
       * TabularResults::ResultSet
      operationWhichReturnsResultSet(...);
       *
       * TabularResults::ResultSet getMoreResults();
       * };
       * </pre>
       */
      module TabularResults
      {
          // The following constants define the column data types
      for result sets.
          // The actual constant values are equivalent to those
      in XOPEN (and JDBC).
          // The leading 'TYPE_' prefix is used since some of the
      type names are IDL
          // reserved words.

          const long TYPE_BIGINT = -5;
          const long TYPE_BINARY = -2;
          const long TYPE_BIT = -7;
          const long TYPE_CHAR = 1;
          const long TYPE_DATE = 91;
          const long TYPE_DECIMAL = 3;
          const long TYPE_DOUBLE = 8;
          const long TYPE_FLOAT = 6;
          const long TYPE_INTEGER = 4;
          const long TYPE_LONGVARBINARY = -4;
          const long TYPE_LONGVARCHAR = -1;
          const long TYPE_NUMERIC = 2;
          const long TYPE_REAL = 7;
          const long TYPE_SMALLINT = 5;
          const long TYPE_TIME = 92;
          const long TYPE_TIMESTAMP = 93;
          const long TYPE_TINYINT = -6;
          const long TYPE_VARBINARY = -3;
          const long TYPE_VARCHAR = 12;

          // The following constants define flags for result
      columns. These are
          // used to convey meta-data which is not indicated by
      the column type.

          const unsigned long FLAG_AUTO_INCREMENT = 1;
          const unsigned long FLAG_CASE_SENSITIVE = 2;
          const unsigned long FLAG_CURRENCY = 4;
          const unsigned long FLAG_NOT_NULLABLE = 8;
          const unsigned long FLAG_NULLABLE = 16;
          const unsigned long FLAG_READONLY = 32;
          const unsigned long FLAG_SEARCHABLE = 64;
          const unsigned long FLAG_UNSIGNED = 128;
          const unsigned long FLAG_WRITABLE = 256;
          const unsigned long FLAG_DEFINITELY_WRITABLE = 512;

          typedef sequence < boolean > BooleanSeq;
          typedef sequence < octet > OctetSeq;
          typedef sequence < short > ShortSeq;
          typedef sequence < long > LongSeq;
          typedef sequence < float > FloatSeq;
          typedef sequence < double > DoubleSeq;
          typedef sequence < string > StringSeq;
          typedef sequence < BCD::Binary > BinarySeq;
          typedef sequence < BCD::Decimal > DecimalSeq;
          typedef sequence < MJD::Date > DateSeq;
          typedef sequence < MJD::Time > TimeSeq;
          typedef sequence < MJD::Timestamp > TimestampSeq;

          /*
           * The <code>Data</code> type represents an entire
      column in a result set.
           * Data is stored in a result set in column-major
      order. This means the
           * column data type (the union discriminator) only
      needs to be transmitted
           * over the network once, and minimises padding when
      using GIOP.
           *
           * <p>Notes:
           * <ul>
           * <li>Type BIGINT uses BCD::Decimal because some CORBA
      ORBs do not support
           * the IDL "long long" type that was introduced with
      CORBA 2.1 / GIOP 1.1.
           * </ul>
           */
          union Data switch (long)
          {
              case TYPE_BIT : BooleanSeq booleanValues;

              case TYPE_TINYINT : OctetSeq octetValues;

              case TYPE_SMALLINT : ShortSeq shortValues;

              case TYPE_INTEGER : LongSeq longValues;

              case TYPE_REAL : FloatSeq floatValues;

              case TYPE_DOUBLE :
              case TYPE_FLOAT : DoubleSeq doubleValues;

              case TYPE_CHAR :
              case TYPE_LONGVARCHAR :
              case TYPE_VARCHAR : StringSeq stringValues;

              case TYPE_BINARY :
              case TYPE_LONGVARBINARY :
              case TYPE_VARBINARY : BinarySeq binaryValues;

              case TYPE_BIGINT :
              case TYPE_DECIMAL :
              case TYPE_NUMERIC : DecimalSeq decimalValues;

              case TYPE_DATE : DateSeq dateValues;

              case TYPE_TIME : TimeSeq timeValues;

              case TYPE_TIMESTAMP : TimestampSeq
      timestampValues;
          };

          /*
           * A result column consists of meta data and data
      values, as well as
           * a sequence indicating which rows contain null
      values. The length of
           * 'nulls' may be less than the number of result rows.
      The default value
           * if a row's 'nulls' entry is not present is false
      (i.e. non-null). This
           * optimisation is particularly useful when the
      column's 'flags' contains
           * the FLAG_NOT_NULLABLE bit.
           * <p>The precision for floating-point decimal values
      is calculated as
           * 'width - sign - dot', where sign = 1 if the flags
      bit FLAG_UNSIGNED
           * is set (otherwise sign = 0), and dot = 1 if scale >
      0 (otherwise
           * dot = 0).
           * <p>The scale must be zero for TYPE_BIGINT.
           */
          struct Column
          {
              unsigned long flags; // Column's meta-data flags
              unsigned long width; // Column's normal display
      width in characters
              unsigned long scale; // Column's scale for fixed-
      point decimal values
              string name; // Column's name
              string label; // Column's label (may be
      empty if equal to name)
              Data values; // Data values for this column
      (for all rows)
              BooleanSeq nulls; // May be less than the number
      of rows
          };

          typedef sequence < Column > ColumnSeq;

          /*
           * The <code>ResultSet</code> type may be used as the
      return type
           * for an operation returning a single result set.
           */
          struct ResultSet
          {
              unsigned long rows;
              ColumnSeq columns;
          };

          /*
           * The <code>ResultSets</code> type may be used as the
      return type
           * for an operation returning multiple result sets.
           */
          typedef sequence<ResultSet> ResultSets;
      };


      -------
      BCD.idl
      -------

      /**
       ** This module defines generic binary (octet sequence)
      types, and arbitrary
       ** precision floating-point decimal data types.
       ** <p>For generic coding, the decimal types are a useful
      alternative to the IDL
       ** <code>fixed</code> template types which were introduced
      by CORBA 2.1 and
       ** GIOP 1.1, since the use of template types introduces a
      distinct type for
       ** each combination of precision and scale.
       **/
      module BCD
      {
          /**
           ** A generic octet sequence type.
           **/
          typedef sequence < octet > Binary;
          /**
           ** <p>A floating-point decimal type.
           ** <p>The <code>Binary</code> representation of
      floating-point values is
           ** designed to support easy conversion to and from
      strings, while at the
           ** same time minimising the size of the binary
      representation for GIOP.
           ** <p>A number is converted to the binary
      representation using the
           ** following algorithm.
           ** <ul>
           ** <li>Convert the number to a decimal string, with a
      leading '-' if
           ** negative, and no leading sign if zero or positive.
           ** <li>The string may contain a decimal point. If the
      number's scale is
           ** greater than zero, the decimal point is followed by
      the number's decimal
           ** fraction. The number of digits in the fraction
      indicates the scale;
           ** trailing zeroes should not be truncated as that
      would reduce the implied
           ** scale.
           ** <li>Convert the string's characters to an octet
      sequence where each
           ** half-octet represents padding, a decimal digit,
      negative sign, or
           ** decimal point, as follows:
           ** <ul>
           ** <li>If the string length is odd, the initial half-
      octet value is 12.
           ** This is used as padding to ensure an even number of
      half-octets.
           ** <li>'0' to '9' map to half-octet values 0 to 9.
           ** <li>'.' maps to half-octet value 10.
           ** <li>'-' maps to half-octet value 13.
           ** </ul>
           ** <li>In each octet of the sequence, the most
      significant half-octet is
           ** filled first. Thus the value "-9" would be encoded
      as octet value
           ** <code>13 * 16 + 9 = 217</code>.
           ** </ul>
           ** <p>Any program receiving a binary value which is
      not formed according
           ** to the above specification should raise a
      CORBA::DATA_CONVERSION system
           ** exception.
           ** <p>Note: a struct is used because it allows
      overloaded methods to be
           ** defined in C++ and Java for decimal manipulation.
      It also guarantees
           ** that a distinct type is generated for the Java IDL
      language mapping.
           **/
          struct Decimal
          {
              Binary value;
          };
          /**
           ** <p>A floating-point decimal (money) type. Uses the
      same representation
           ** as <code>Decimal</code> but may be used where a
      semantic distinction is
           ** required.
           ** <p>Note: a struct is used because it allows
      overloaded methods to be
           ** defined in C++ and Java for money manipulation. It
      also guarantees
           ** that a distinct type is generated for the Java IDL
      language mapping.
           **/
          struct Money
          {
              Binary value;
          };
      };


      -------
      MJD.idl
      -------

      /*
       * This module defines date/time types based on the
      Modified Astronomical
       * Julian Date (M.J.D.) standard. The Modified Julian Date
      is given in
       * decimal form, not in hours and minutes.
       *
       * <p>Source: Norton's Star Atlas and Reference Handbook,
      17th edition.
       */
      module MJD
      {
          /*
           * The <code>Date</code> type encodes a date/time as
      J.D. - 2,400,000.5,
           * where J.D. = 0 represents Jan 1, 4713 B.C. at
      Greenwich noon.
           * For example, Greenwich midnight Jan 1, 1970 is
      M.J.D. 40222.0.
           * <p>This type provides millsecond resolution for
      dates at least
           * 10,000 years either side of the base value (MJD =
      0.0).
           * <p>Note: a struct is used because it allows
      overloaded methods to be
           * defined in C++ and Java for date manipulation.
           */
          struct Date
          {
              double dateValue;
          };

          /*
           * The <code>Time</code> type encodes a time with
      nanosecond
           * resolution. The encoded value <code>timeValue</code>
      is equivalent
           * to <code>Date's</code> dateValue, but only the
      fractional part of
           * <code>timeValue</code> is understood to have
      significance.
           * The integral part should be zero, since any
      significant digits in
           * the integral part reduce the precision of the time
      value.
           * <p>Note: a struct is used because it allows
      overloaded methods to be
           * defined in C++ and Java for time manipulation.
           */
          struct Time
          {
              double timeValue;
          };

          /*
           * The <code>Timestamp</code> type encodes a date/time
      with nanosecond
           * resolution. The encoded value dateValue + timeValue
      is equivalent
           * to <code>Date's</code> dateValue, but allows for
      nanosecond resolution.
           * To ensure no loss of significance,
      <code>dateValue</code> must be
           * integral (may be negative) and <code>0 <=
      timeValue < 1</code>.
           * <p>This type provides nanosecond resolution for
      dates at least
           * 100,000,000,000 years either side of the base value
      (MJD = 0.0).
           */
          struct Timestamp
          {
              double dateValue;
              double timeValue;
          };
      };

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Compile the IDL files using idlj.


      REPRODUCIBILITY :
      This bug can be reproduced always.

      CUSTOMER WORKAROUND :
      Nobble the DataHelper.read() so that it passes the
      discriminat

            kcavanauorcl Ken Cavanaugh (Inactive)
            nthompsosunw Nathanael Thompson (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: