# Record.java

    /*
    ** Module   : Record.java
    ** Abstract : The abstract base class for all business data model object classes.
    **
    ** Copyright (c) 2019-2025, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- ---------------------------------------Description---------------------------------------
    ** 001 ECF 20191001 Created initial version with basic data and accessors.
    **     OM  20200110 Added support various data types and setter/getter signatures.
    ** 002 AIL 20200826 Handle getters should use a string to handle conversion without zero default
    **                  for invalid resources.
    ** 003 OM  20201213 Added utility method used for debugging.
    **     CA  20210305 The object and handle fields have a Long representation at the SQL table field.
    **     OM  20210404 CLOB fields are created and returned with their CP set.
    **     ECF 20210519 Added APIs to increment/decrement reference count for "in-use" tracking.
    **     OM  20210618 Adjusted toString2() so that the method can be used to report broken records detected
    **                  at import time.
    **     OM  20210806 Fixed getter for unknown raw values.
    **     CA  20220329 Added methods which get the record's property to a map (with keys the legacy field names),
    **                  and which allows to populate the record from such a map.  This is used by REST services
    **                  written directly in Java, to serialize any record parameters.
    **     OM  20220713 Added support for converting to/from POJOs.
    **     OM  20220718 Fixed looping in getPropertyValues(). Added to the returned list the denormalized props.
    **     TJD 20220504 Upgrade do Java 11 minor changes
    **     CA  20221109 Implemented runtime for EXCEPT/FIELDS options - only NO-LOCK records are loaded as
    **                  'partial/incomplete'.
    ** 004 SBI 20260226 Extracted getPropertyValues into PropertiesDescriptor interface.
    ** 005 CA  20230928 Force the type of an unknown object field to 'Progress.Lang.Object'.
    ** 006 CA  20240324 Use logical constants for TRUE, FALSE, UNKNOWN, within internal FWD runtime.
    ** 007 CA  20240403 Backed out CA/006 - the returned getter instance can be used by internal runtime.
    ** 008 AL2 20240409 Added isMultiplyReferenced and reworked the reference counting.
    ** 009 TJD 20240123 Java 17 compatibility updates
    ** 010 CA  20241030 Avoid 'Text.javaSpacifyNull' if the string is known to already have been processed.
    ** 011 AP  20250226 Added method for fast equality checking of data arrays.
    */

    /*
    ** This program is free software: you can redistribute it and/or modify
    ** it under the terms of the GNU Affero General Public License as
    ** published by the Free Software Foundation, either version 3 of the
    ** License, or (at your option) any later version.
    **
    ** This program is distributed in the hope that it will be useful,
    ** but WITHOUT ANY WARRANTY; without even the implied warranty of
    ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    ** GNU Affero General Public License for more details.
    **
    ** You may find a copy of the GNU Affero GPL version 3 at the following
    ** location: https://www.gnu.org/licenses/agpl-3.0.en.html
    **
    ** Additional terms under GNU Affero GPL version 3 section 7:
    **
    **   Under Section 7 of the GNU Affero GPL version 3, the following additional
    **   terms apply to the works covered under the License.  These additional terms
    **   are non-permissive additional terms allowed under Section 7 of the GNU
    **   Affero GPL version 3 and may not be removed by you.
    **
    **   0. Attribution Requirement.
    **
    **     You must preserve all legal notices or author attributions in the covered
    **     work or Appropriate Legal Notices displayed by works containing the covered
    **     work.  You may not remove from the covered work any author or developer
    **     credit already included within the covered work.
    **
    **   1. No License To Use Trademarks.
    **
    **     This license does not grant any license or rights to use the trademarks
    **     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
    **     of Golden Code Development Corporation. You are not authorized to use the
    **     name Golden Code, FWD, or the names of any author or contributor, for
    **     publicity purposes without written authorization.
    **
    **   2. No Misrepresentation of Affiliation.
    **
    **     You may not represent yourself as Golden Code Development Corporation or FWD.
    **
    **     You may not represent yourself for publicity purposes as associated with
    **     Golden Code Development Corporation, FWD, or any author or contributor to
    **     the covered work, without written authorization.
    **
    **   3. No Misrepresentation of Source or Origin.
    **
    **     You may not represent the covered work as solely your work.  All modified
    **     versions of the covered work must be marked in a reasonable way to make it
    **     clear that the modified work is not originating from Golden Code Development
    **     Corporation or FWD.  All modified versions must contain the notices of
    **     attribution required in this license.
    */

    package com.goldencode.p2j.persist;

    import java.lang.reflect.Array;
    import java.lang.reflect.InvocationTargetException;
    import java.math.*;
    import java.sql.*;
    import java.sql.Date;
    import java.time.*;
    import java.util.*;
    import java.util.function.*;

    import com.goldencode.p2j.oo.lang.BaseObject;
    import com.goldencode.p2j.persist.orm.*;
    import com.goldencode.p2j.util.*;

    /**
     * The abstract base class for all business data model object classes. Provides an API for a
     * concrete implementation to access the low level data of this object as FWD data wrapper types.
     * Subclasses are intended to be generated at runtime, rather than coded by hand.
     */
    public abstract class Record
    extends BaseRecord
    implements PropertiesDescriptor
    {
       /**
        * Default constructor needed by DMOs extending this class.
        */
       protected Record()
       {
          super();
       }

       /**
        * Creates a snapshot copy of the current record.
        *
        * @return  a new {@code Record} instance of this record with all fields set to values of the
        *          respective fields in this {@code Record} at the moment of the call.
        */
       public Record snapshot()
       {
          try
          {
             Record shot = getClass().getDeclaredConstructor().newInstance();
             shot.copy(this);
             shot.state.state |= COPY;

             return shot;
          }
          catch (ReflectiveOperationException |
                 IllegalArgumentException     |
                 SecurityException e)
          {
             throw new RuntimeException(e); // PersistenceException (?)
          }
       }

       /**
        * Get an {@code integer} value for the datum at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset from which to retrieve the value from the property array.
        *
        * @return  The datum as an {@code integer}; will represent unknown value if the datum is
        *          {@code null}.
        */
       public final integer _getInteger(int offset)
       {
          checkIncomplete(offset);

          Integer datum = (Integer) data[offset];

          return datum != null ? new integer(datum) : new integer();
       }

       /**
        * Set an {@code integer} value into the data at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset at which to store the given datum in the property array.
        * @param   w
        *          FWD wrapper type for the integral value.
        */
       protected final void _setInteger(int offset, NumberType w)
       {
          Integer datum = null;
          if (w != null)
          {
             integer num = (w instanceof integer) ? (integer) w : new integer(w);
             if (!num.isUnknown())
             {
                datum = num.toJavaIntegerType();
             }
          }

          setDatum(offset, datum);
       }

       /**
        * Bulk getter for a {@code integer} extent field. All components are returned as a single
        * array of {@code integer}.
        *
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        *
        * @return  An array of {@code integer} representing the elements of an extent field.
        */
       protected final integer[] _getInteger(int extent, int offset)
       {
          integer[] ret = new integer[extent];
          for (int k = 0; k < extent; k++)
          {
             ret[k] = _getInteger(offset + k);
          }

          return ret;
       }

       /**
        * Bulk setter for a {@code NumberType} extent field. Each components from {@code val}
        * parameter will initialize their correspondent of the extent field in {@code data} array.
        *
        * @param   val
        *          An array of {@code NumberType} values to be used for setting the extent field.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setInteger(NumberType[] val, int extent, int offset)
       {
          int len = Math.min(val.length, extent);

          for (int k = 0; k < len; k++)
          {
             _setInteger(offset + k, val[k]);
          }
       }

       /**
        * Mass setter for a {@code NumberType} extent field. All components of the extent field will
        * be set to {@code val} in {@code data} array.
        *
        * @param   val
        *          A {@code NumberType} value to be used for setting the extent field components.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setInteger(NumberType val, int extent, int offset)
       {
          for (int k = 0; k < extent; k++)
          {
             _setInteger(offset + k, val);
          }
       }

       /**
        * Get an {@code datetimetz} value for the datum at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset from which to retrieve the value from the property array.
        *
        * @return  The datum as an {@code datetimetz}; will represent unknown value if the datum is
        *          {@code null}.
        */
       public final datetimetz _getDatetimetz(int offset)
       {
          checkIncomplete(offset);

          OffsetDateTime datum = (OffsetDateTime) data[offset];

          return datum != null ? new datetimetz(datum) : new datetimetz();
       }

       /**
        * Set an {@code datetimetz} value into the data at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset at which to store the given datum in the property array.
        * @param   w
        *          FWD wrapper type for the integral value.
        */
       protected final void _setDatetimetz(int offset, date w)
       {
          OffsetDateTime datum = null;
          if (w != null && !w.isUnknown())
          {
             datetimetz dtz = w instanceof datetimetz ? (datetimetz) w : new datetimetz(w);
             datum = dtz.offsetDateTimeValue();
          }

          setDatum(offset, datum);
       }

       /**
        * Bulk getter for a {@code datetimetz} extent field. All components are returned as a single
        * array of {@code datetimetz}.
        *
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        *
        * @return  An array of {@code datetimetz} representing the elements of an extent field.
        */
       protected final datetimetz[] _getDatetimetz(int extent, int offset)
       {
          datetimetz[] ret = new datetimetz[extent];
          for (int k = 0; k < extent; k++)
          {
             ret[k] = _getDatetimetz(offset + k);
          }

          return ret;
       }

       /**
        * Bulk setter for a {@code datetimetz} extent field. Each components from {@code val}
        * parameter will initialize their correspondent of the extent field in {@code data} array.
        *
        * @param   val
        *          An array of {@code date} values to be used for setting the extent field.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setDatetimetz(date[] val, int extent, int offset)
       {
          int len = Math.min(val.length, extent);

          for (int k = 0; k < len; k++)
          {
             _setDatetimetz(offset + k, val[k]);
          }
       }

       /**
        * Mass setter for a {@code datetimetz} extent field. All components of the extent field will
        * be set to {@code val} in {@code data} array.
        *
        * @param   val
        *          A {@code date} value to be used for setting the extent field components.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setDatetimetz(date val, int extent, int offset)
       {
          for (int k = 0; k < extent; k++)
          {
             _setDatetimetz(offset + k, val);
          }
       }

       /**
        * Get an {@code datetime} value for the datum at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset from which to retrieve the value from the property array.
        *
        * @return  The datum as an {@code datetime}; will represent unknown value if the datum is
        *          {@code null}.
        */
       public final datetime _getDatetime(int offset)
       {
          checkIncomplete(offset);

          Timestamp datum = (Timestamp) data[offset];

          return datum != null ? new datetime(datum) : new datetime();
       }

       /**
        * Set an {@code datetime} value into the data at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset at which to store the given datum in the property array.
        * @param   w
        *          FWD wrapper type for the integral value.
        */
       protected final void _setDatetime(int offset, date w)
       {
          Timestamp datum = null;
          if (w != null && !w.isUnknown())
          {
             datum = new Timestamp(w.dateValue().getTime());
          }

          setDatum(offset, datum);
       }

       /**
        * Bulk getter for a {@code datetime} extent field. All components are returned as a single
        * array of {@code datetime}.
        *
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        *
        * @return  An array of {@code datetime} representing the elements of an extent field.
        */
       protected final datetime[] _getDatetime(int extent, int offset)
       {
          datetime[] ret = new datetime[extent];
          for (int k = 0; k < extent; k++)
          {
             ret[k] = _getDatetime(offset + k);
          }

          return ret;
       }

       /**
        * Bulk setter for a {@code datetime} extent field. Each components from {@code val}
        * parameter will initialize their correspondent of the extent field in {@code data} array.
        *
        * @param   val
        *          An array of {@code datetime} values to be used for setting the extent field.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setDatetime(date[] val, int extent, int offset)
       {
          int len = Math.min(val.length, extent);

          for (int k = 0; k < len; k++)
          {
             _setDatetime(offset + k, val[k]);
          }
       }

       /**
        * Mass setter for a {@code datetime} extent field. All components of the extent field will
        * be set to {@code val} in {@code data} array.
        *
        * @param   val
        *          A {@code date} value to be used for setting the extent field components.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setDatetime(date val, int extent, int offset)
       {
          for (int k = 0; k < extent; k++)
          {
             _setDatetime(offset + k, val);
          }
       }

       /**
        * Get an {@code date} value for the datum at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset from which to retrieve the value from the property array.
        *
        * @return  The datum as an {@code date}; will represent unknown value if the datum is
        *          {@code null}.
        */
       public final date _getDate(int offset)
       {
          checkIncomplete(offset);

          Date datum = (Date) data[offset];

          return datum != null ? new date(datum) : new date();
       }

       /**
        * Set an {@code date} value into the data at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset at which to store the given datum in the property array.
        * @param   d
        *          FWD wrapper type for the integral value.
        */
       protected final void _setDate(int offset, date d)
       {
          Date datum = null;
          if (d != null && !d.isUnknown())
          {
             datum = new Date(d.dateValue(null).getTime());
          }

          setDatum(offset, datum);
       }

       /**
        * Bulk getter for a {@code date} extent field. All components are returned as a single
        * array of {@code date}.
        *
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        *
        * @return  An array of {@code date} representing the elements of an extent field.
        */
       protected final date[] _getDate(int extent, int offset)
       {
          date[] ret = new date[extent];
          for (int k = 0; k < extent; k++)
          {
             ret[k] = _getDate(offset + k);
          }

          return ret;
       }

       /**
        * Bulk setter for a {@code date} extent field. Each components from {@code val}
        * parameter will initialize their correspondent of the extent field in {@code data} array.
        *
        * @param   val
        *          An array of {@code date} values to be used for setting the extent field.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setDate(date[] val, int extent, int offset)
       {
          int len = Math.min(val.length, extent);

          for (int k = 0; k < len; k++)
          {
             _setDate(offset + k, val[k]);
          }
       }

       /**
        * Mass setter for a {@code date} extent field. All components of the extent field will
        * be set to {@code val} in {@code data} array.
        *
        * @param   val
        *          A {@code date} value to be used for setting the extent field components.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setDate(date val, int extent, int offset)
       {
          for (int k = 0; k < extent; k++)
          {
             _setDate(offset + k, val);
          }
       }

       /**
        * Get an {@code integer} value for the datum at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset from which to retrieve the value from the property array.
        *
        * @return  The datum as an {@code integer}; will represent unknown value if the datum is
        *          {@code null}.
        */
       public final logical _isLogical(int offset)
       {
          checkIncomplete(offset);

          Boolean datum = (Boolean) data[offset];

          return datum != null ? new logical(datum) : new logical();
       }

       /**
        * Set an {@code logical} value into the data at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset at which to store the given datum in the property array.
        * @param   w
        *          FWD wrapper type for the logical value.
        */
       protected final void _setLogical(int offset, logical w)
       {
          Boolean datum = null;
          if (w != null && !w.isUnknown())
          {
             datum = w.booleanValue();
          }

          setDatum(offset, datum);
       }

       /**
        * Bulk getter for a {@code logical} extent field. All components are returned as a single
        * array of {@code logical}.
        *
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        *
        * @return  An array of {@code logical} representing the elements of an extent field.
        */
       protected final logical[] _isLogical(int extent, int offset)
       {
          logical[] ret = new logical[extent];
          for (int k = 0; k < extent; k++)
          {
             ret[k] = _isLogical(offset + k);
          }

          return ret;
       }

       /**
        * Bulk setter for a {@code logical} extent field. Each components from {@code val} parameter
        * will initialize their correspondent of the extent field in {@code data} array.
        *
        * @param   val
        *          An array of {@code logical} values to be used for setting the extent field.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setLogical(logical[] val, int extent, int offset)
       {
          int len = Math.min(val.length, extent);

          for (int k = 0; k < len; k++)
          {
             _setLogical(offset + k, val[k]);
          }
       }

       /**
        * Mass setter for a {@code logical} extent field. All components of the extent field will be
        * set to {@code val} in {@code data} array.
        *
        * @param   val
        *          A {@code logical} value to be used for setting the extent field components.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setLogical(logical val, int extent, int offset)
       {
          for (int k = 0; k < extent; k++)
          {
             _setLogical(offset + k, val);
          }
       }

       /**
        * Get an {@code int64} value for the datum at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset from which to retrieve the value from the property array.
        *
        * @return  The datum as an {@code int64}; will represent unknown value if the datum is
        *          {@code null}.
        */
       public final int64 _getInt64(int offset)
       {
          Long datum = (Long) data[offset];

          return datum != null ? new int64(datum) : new int64();
       }

       /**
        * Set an {@code integer} value into the data at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset at which to store the given datum in the property array.
        * @param   w
        *          FWD wrapper type for the integral value.
        */
       protected final void _setInt64(int offset, NumberType w)
       {
          Long datum = null;
          if (w != null)
          {
             int64 num = (w instanceof int64) ? (int64) w : new int64(w);
             if (!num.isUnknown())
             {
                datum = num.toJavaLongType();
             }
          }

          setDatum(offset, datum);
       }

       /**
        * Bulk getter for a {@code int64} extent field. All components are returned as a single
        * array of {@code int64}.
        *
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        *
        * @return  An array of {@code int64} representing the elements of an extent field.
        */
       protected final int64[] _getInt64(int extent, int offset)
       {
          int64[] ret = new int64[extent];
          for (int k = 0; k < extent; k++)
          {
             ret[k] = _getInt64(offset + k);
          }

          return ret;
       }

       /**
        * Bulk setter for a {@code NumberType} extent field. Each components from {@code val}
        * parameter will initialize their correspondent of the extent field in {@code data} array.
        *
        * @param   val
        *          An array of {@code NumberType} values to be used for setting the extent field.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setInt64(NumberType[] val, int extent, int offset)
       {
          int len = Math.min(val.length, extent);

          for (int k = 0; k < len; k++)
          {
             _setInt64(offset + k, val[k]);
          }
       }

       /**
        * Mass setter for a {@code NumberType} extent field. All components of the extent field will
        * be set to {@code val} in {@code data} array.
        *
        * @param   val
        *          A {@code NumberType} value to be used for setting the extent field components.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setInt64(NumberType val, int extent, int offset)
       {
          for (int k = 0; k < extent; k++)
          {
             _setInt64(offset + k, val);
          }
       }

       /**
        * Get a {@code decimal} value for the datum at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset from which to retrieve the value from the property array.
        *
        * @return  The datum as a {@code decimal}; will represent unknown value if the datum is
        *          {@code null}.
        */
       public final decimal _getDecimal(int offset)
       {
          checkIncomplete(offset);

          BigDecimal datum = (BigDecimal) data[offset];

          return datum != null ? new decimal(datum) : new decimal();
       }

       /**
        * Set a {@code decimal} value into the data at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset at which to store the given datum in the property array.
        * @param   w
        *          FWD wrapper type for the decimal value.
        */
       protected final void _setDecimal(int offset, NumberType w)
       {
          BigDecimal datum = null;
          if (w != null)
          {
             decimal num = (w instanceof decimal) ? (decimal) w : new decimal(w);

             if (!num.isUnknown())
             {
                datum = num.toJavaType();
                int scale = num.getPrecision();

                int propScale = _recordMeta().getPropertyMeta(false)[offset].getDecimals();
                if (propScale != scale)
                {
                   datum = datum.setScale(propScale, RoundingMode.HALF_UP);
                }
             }
          }

          setDatum(offset, datum);
       }

       /**
        * Bulk getter for a {@code integer} extent field. All components are returned as a single
        * array of {@code integer}.
        *
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        *
        * @return  An array of {@code integer} representing the elements of an extent field.
        */
       protected final decimal[] _getDecimal(int extent, int offset)
       {
          decimal[] ret = new decimal[extent];
          for (int k = 0; k < extent; k++)
          {
             ret[k] = _getDecimal(offset + k);
          }

          return ret;
       }

       /**
        * Bulk setter for a {@code NumberType} extent field. Each components from {@code val}
        * parameter will initialize their correspondent of the extent field in {@code data} array.
        *
        * @param   val
        *          An array of {@code NumberType} values to be used for setting the extent field.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setDecimal(NumberType[] val, int extent, int offset)
       {
          int len = Math.min(val.length, extent);

          for (int k = 0; k < len; k++)
          {
             _setDecimal(offset + k, val[k]);
          }
       }

       /**
        * Mass setter for a {@code NumberType} extent field. All components of the extent field will
        * be set to {@code val} in {@code data} array.
        *
        * @param   val
        *          A {@code NumberType} value to be used for setting the extent field components.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setDecimal(NumberType val, int extent, int offset)
       {
          for (int k = 0; k < extent; k++)
          {
             _setDecimal(offset + k, val);
          }
       }

       /**
        * Get a {@code character} value for the datum at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset from which to retrieve the value from the property array.
        *
        * @return  The datum as a {@code character}; will represent unknown value if the datum is
        *          {@code null}. The value will have the case-sensitivity inherent to the
        *          corresponding field.
        */
       public final character _getCharacter(int offset)
       {
          checkIncomplete(offset);

          String datum = (String) data[offset];

          if (datum != null)
          {
             return new character(datum, _recordMeta().getPropertyMeta(false)[offset].isCaseSensitive(), false);
          }

          return new character();
       }

       /**
        * Set a {@code character} value into the data at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset at which to store the given datum in the property array.
        * @param   w
        *          FWD wrapper type for the character value. The case-sensitivity property of this
        *          wrapper instance is not preserved.
        */
       protected final void _setCharacter(int offset, Text w)
       {
          String datum = null;
          if (w != null && !w.isUnknown())
          {
             datum = w.toJavaType();
          }

          setDatum(offset, datum);
       }

       /**
        * Bulk getter for a {@code character} extent field. All components are returned as a single
        * array of {@code character}.
        *
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        *
        * @return  An array of {@code character} representing the elements of an extent field.
        */
       protected final character[] _getCharacter(int extent, int offset)
       {
          character[] ret = new character[extent];
          for (int k = 0; k < extent; k++)
          {
             ret[k] = _getCharacter(offset + k);
          }

          return ret;
       }

       /**
        * Bulk setter for a {@code Text} extent field. Each components from {@code val}
        * parameter will initialize their correspondent of the extent field in {@code data} array.
        *
        * @param   val
        *          An array of {@code Text} values to be used for setting the extent field.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setCharacter(Text[] val, int extent, int offset)
       {
          int len = Math.min(val.length, extent);

          for (int k = 0; k < len; k++)
          {
             _setCharacter(offset + k, val[k]);
          }
       }

       /**
        * Mass setter for a {@code Text} extent field. All components of the extent field will
        * be set to {@code val} in {@code data} array.
        *
        * @param   val
        *          A {@code Text} value to be used for setting the extent field components.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setCharacter(Text val, int extent, int offset)
       {
          for (int k = 0; k < extent; k++)
          {
             _setCharacter(offset + k, val);
          }
       }

       /**
        * Get a {@code rowid} value for the datum at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset from which to retrieve the value from the property array.
        *
        * @return  The datum as a {@code rowid}; will represent unknown value if the datum is
        *          {@code null}. The value will have the case-sensitivity inherent to the
        *          corresponding field.
        */
       public final rowid _getRowid(int offset)
       {
          checkIncomplete(offset);

          Long datum = (Long) data[offset];

          return datum != null ? new rowid(datum) : new rowid();
       }

       /**
        * Set a {@code rowid} value into the data at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset at which to store the given datum in the property array.
        * @param   w
        *          FWD wrapper type for the rowid value. The case-sensitivity property of this
        *          wrapper instance is not preserved.
        */
       protected final void _setRowid(int offset, rowid w)
       {
          Long datum = null;
          if (w != null && !w.isUnknown())
          {
             datum = w.getValue();
          }

          setDatum(offset, datum);
       }

       /**
        * Bulk getter for a {@code rowid} extent field. All components are returned as a single
        * array of {@code rowid}.
        *
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        *
        * @return  An array of {@code rowid} representing the elements of an extent field.
        */
       protected final rowid[] _getRowid(int extent, int offset)
       {
          rowid[] ret = new rowid[extent];
          for (int k = 0; k < extent; k++)
          {
             ret[k] = _getRowid(offset + k);
          }

          return ret;
       }

       /**
        * Bulk setter for a {@code rowid} extent field. Each components from {@code val}
        * parameter will initialize their correspondent of the extent field in {@code data} array.
        *
        * @param   val
        *          An array of {@code rowid} values to be used for setting the extent field.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setRowid(rowid[] val, int extent, int offset)
       {
          int len = Math.min(val.length, extent);

          for (int k = 0; k < len; k++)
          {
             _setRowid(offset + k, val[k]);
          }
       }

       /**
        * Mass setter for a {@code rowid} extent field. All components of the extent field will
        * be set to {@code val} in {@code data} array.
        *
        * @param   val
        *          A {@code rowid} value to be used for setting the extent field components.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setRowid(rowid val, int extent, int offset)
       {
          for (int k = 0; k < extent; k++)
          {
             _setRowid(offset + k, val);
          }
       }

       /**
        * Get a {@code handle} value for the datum at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset from which to retrieve the value from the property array.
        *
        * @return  The datum as a {@code handle}; will represent unknown value if the datum is
        *          {@code null}. The value will have the case-sensitivity inherent to the
        *          corresponding field.
        */
       public final handle _getHandle(int offset)
       {
          checkIncomplete(offset);

          Long datum = (Long) data[offset];

          return datum != null ? handle.fromResourceId(datum, false) : new handle();
       }

       /**
        * Set a {@code handle} value into the data at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset at which to store the given datum in the property array.
        * @param   w
        *          FWD wrapper type for the handle value. The case-sensitivity property of this
        *          wrapper instance is not preserved.
        */
       protected final void _setHandle(int offset, handle w)
       {
          Long datum = null;
          if (w != null && !w.isUnknown())
          {
             datum = w.getResourceId();
          }

          setDatum(offset, datum);
       }

       /**
        * Bulk getter for a {@code handle} extent field. All components are returned as a single
        * array of {@code handle}.
        *
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        *
        * @return  An array of {@code handle} representing the elements of an extent field.
        */
       protected final handle[] _getHandle(int extent, int offset)
       {
          handle[] ret = new handle[extent];
          for (int k = 0; k < extent; k++)
          {
             ret[k] = _getHandle(offset + k);
          }

          return ret;
       }

       /**
        * Bulk setter for a {@code handle} extent field. Each components from {@code val}
        * parameter will initialize their correspondent of the extent field in {@code data} array.
        *
        * @param   val
        *          An array of {@code handle} values to be used for setting the extent field.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setHandle(handle[] val, int extent, int offset)
       {
          int len = Math.min(val.length, extent);

          for (int k = 0; k < len; k++)
          {
             _setHandle(offset + k, val[k]);
          }
       }

       /**
        * Mass setter for a {@code handle} extent field. All components of the extent field will
        * be set to {@code val} in {@code data} array.
        *
        * @param   val
        *          A {@code handle} value to be used for setting the extent field components.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setHandle(handle val, int extent, int offset)
       {
          for (int k = 0; k < extent; k++)
          {
             _setHandle(offset + k, val);
          }
       }

       /**
        * Get a {@code recid} value for the datum at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset from which to retrieve the value from the property array.
        *
        * @return  The datum as a {@code recid}; will represent unknown value if the datum is
        *          {@code null}. The value will have the case-sensitivity inherent to the
        *          corresponding field.
        */
       public final recid _getRecid(int offset)
       {
          checkIncomplete(offset);

          Integer datum = (Integer) data[offset];

          return datum != null ? new recid(datum) : new recid();
       }

       /**
        * Set a {@code recid} value into the data at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset at which to store the given datum in the property array.
        * @param   w
        *          FWD wrapper type for the {@code recid} value. The case-sensitivity property of this
        *          wrapper instance is not preserved.
        */
       protected final void _setRecid(int offset, NumberType w)
       {
          Integer datum = null;
          if (w != null && !w.isUnknown())
          {
             datum = w.intValue();
          }

          setDatum(offset, datum);
       }

       /**
        * Bulk getter for a {@code recid} extent field. All components are returned as a single
        * array of {@code recid}.
        *
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        *
        * @return  An array of {@code recid} representing the elements of an extent field.
        */
       protected final recid[] _getRecid(int extent, int offset)
       {
          recid[] ret = new recid[extent];
          for (int k = 0; k < extent; k++)
          {
             ret[k] = _getRecid(offset + k);
          }

          return ret;
       }

       /**
        * Bulk setter for a {@code recid} extent field. Each components from {@code val}
        * parameter will initialize their correspondent of the extent field in {@code data} array.
        *
        * @param   val
        *          An array of {@code recid} values to be used for setting the extent field.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setRecid(recid[] val, int extent, int offset)
       {
          int len = Math.min(val.length, extent);

          for (int k = 0; k < len; k++)
          {
             _setRecid(offset + k, val[k]);
          }
       }

       /**
        * Mass setter for a {@code recid} extent field. All components of the extent field will
        * be set to {@code val} in {@code data} array.
        *
        * @param   val
        *          A {@code recid} value to be used for setting the extent field components.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setRecid(NumberType val, int extent, int offset)
       {
          for (int k = 0; k < extent; k++)
          {
             _setRecid(offset + k, val);
          }
       }

       /**
        * Get an {@code blob} value for the datum at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset from which to retrieve the value from the property array.
        *
        * @return  The datum as an {@code blob}; will represent unknown value if the datum is
        *          {@code null}.
        */
       public final blob _getBlob(int offset)
       {
          checkIncomplete(offset);

          byte[] datum = (byte[]) data[offset];

          return datum != null ? new blob(datum) : new blob();
       }

       /**
        * Bulk getter for a {@code blob} extent field. All components are returned as a single
        * array of {@code blob}.
        *
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        *
        * @return  An array of {@code blob} representing the elements of an extent field.
        */
       protected final blob[] _getBlob(int extent, int offset)
       {
          blob[] ret = new blob[extent];
          for (int k = 0; k < extent; k++)
          {
             ret[k] = _getBlob(offset + k);
          }

          return ret;
       }

       /**
        * Set an {@code blob} value into the data at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset at which to store the given datum in the property array.
        * @param   w
        *          FWD wrapper type for the value.
        */
       protected final void _setBlob(int offset, blob w)
       {
          byte[] datum = null;
          if (w != null && !w.isUnknown())
          {
             datum = w.getByteArray();
          }

          setDatum(offset, datum);
       }

       /**
        * Bulk setter for a {@code blob} extent field. Each components from {@code val}
        * parameter will initialize their correspondent of the extent field in {@code data} array.
        *
        * @param   val
        *          An array of {@code blob} values to be used for setting the extent field.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setBlob(blob[] val, int extent, int offset)
       {
          int len = Math.min(val.length, extent);

          for (int k = 0; k < len; k++)
          {
             _setBlob(offset + k, val[k]);
          }
       }

       /**
        * Mass setter for a {@code blob} extent field. All components of the extent field will
        * be set to {@code val} in {@code data} array.
        *
        * @param   val
        *          A {@code blob} value to be used for setting the extent field components.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setBlob(blob val, int extent, int offset)
       {
          for (int k = 0; k < extent; k++)
          {
             _setBlob(offset + k, val);
          }
       }

       /**
        * Get an {@code clob} value for the datum at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic, and the low-level
        * data storage in the record.
        * <p>
        * Note: in order for this method to work, the {@code activeBuffer} on parent object must be set in
        *       advance. After the method was invoked, it is recommended to clear its value.
        *
        * @param   offset
        *          Zero-based offset from which to retrieve the value from the property array.
        *
        * @return  The datum as an {@code clob}; will represent unknown value if the datum is {@code null}.
        */
       public final clob _getClob(int offset)
       {
          checkIncomplete(offset);

          return new clob((String) data[offset], getCodePage(offset));
       }

       /**
        * Bulk getter for a {@code clob} extent field. All components are returned as a single
        * array of {@code clob}.
        *
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        *
        * @return  An array of {@code clob} representing the elements of an extent field.
        */
       protected final clob[] _getClob(int extent, int offset)
       {
          clob[] ret = new clob[extent];
          for (int k = 0; k < extent; k++)
          {
             ret[k] = _getClob(offset + k);
          }

          return ret;
       }

       /**
        * Set an {@code clob} value into the data at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset at which to store the given datum in the property array.
        * @param   w
        *          FWD wrapper type for the value.
        */
       protected final void _setClob(int offset, clob w)
       {
          String datum = null;
          if (w != null && !w.isUnknown())
          {
             datum = w.toStringExport();
          }

          setDatum(offset, datum);
       }

       /**
        * Bulk setter for a {@code clob} extent field. Each components from {@code val}
        * parameter will initialize their correspondent of the extent field in {@code data} array.
        *
        * @param   val
        *          An array of {@code clob} values to be used for setting the extent field.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setClob(clob[] val, int extent, int offset)
       {
          int len = Math.min(val.length, extent);

          for (int k = 0; k < len; k++)
          {
             _setClob(offset + k, val[k]);
          }
       }

       /**
        * Mass setter for a {@code clob} extent field. All components of the extent field will
        * be set to {@code val} in {@code data} array.
        *
        * @param   val
        *          A {@code clob} value to be used for setting the extent field components.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setClob(clob val, int extent, int offset)
       {
          for (int k = 0; k < extent; k++)
          {
             _setClob(offset + k, val);
          }
       }

       /**
        * Get an {@code comhandle} value for the datum at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset from which to retrieve the value from the property array.
        *
        * @return  The datum as an {@code comhandle}; will represent unknown value if the datum is
        *          {@code null}.
        */
       public final comhandle _getComhandle(int offset)
       {
          checkIncomplete(offset);

          String datum = (String) data[offset];

          return datum != null ? comhandle.fromString(datum) : new comhandle();
       }

       /**
        * Bulk getter for a {@code comhandle} extent field. All components are returned as a single
        * array of {@code comhandle}.
        *
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        *
        * @return  An array of {@code comhandle} representing the elements of an extent field.
        */
       protected final comhandle[] _getComhandle(int extent, int offset)
       {
          comhandle[] ret = new comhandle[extent];
          for (int k = 0; k < extent; k++)
          {
             ret[k] = _getComhandle(offset + k);
          }

          return ret;
       }

       /**
        * Set an {@code comhandle} value into the data at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset at which to store the given datum in the property array.
        * @param   w
        *          FWD wrapper type for the value.
        */
       protected final void _setComhandle(int offset, comhandle w)
       {
          String datum = null;
          if (w != null && !w.isUnknown())
          {
             datum = w.toStringExport();
          }

          setDatum(offset, datum);
       }

       /**
        * Bulk setter for a {@code comhandle} extent field. Each components from {@code val}
        * parameter will initialize their correspondent of the extent field in {@code data} array.
        *
        * @param   val
        *          An array of {@code comhandle} values to be used for setting the extent field.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setComhandle(comhandle[] val, int extent, int offset)
       {
          int len = Math.min(val.length, extent);

          for (int k = 0; k < len; k++)
          {
             _setComhandle(offset + k, val[k]);
          }
       }

       /**
        * Mass setter for a {@code comhandle} extent field. All components of the extent field will
        * be set to {@code val} in {@code data} array.
        *
        * @param   val
        *          A {@code comhandle} value to be used for setting the extent field components.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setComhandle(comhandle val, int extent, int offset)
       {
          for (int k = 0; k < extent; k++)
          {
             _setComhandle(offset + k, val);
          }
       }

       /**
        * Get an {@code object} value for the datum at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset from which to retrieve the value from the property array.
        *
        * @return  The datum as an {@code object}; will represent unknown value if the datum is
        *          {@code null}.
        */
       public final object<?> _getObject(int offset)
       {
          checkIncomplete(offset);

          Long datum = (Long) data[offset];

          // the instance must be typed to Progress.Lang.Object
          object<?> res = new object<>(BaseObject.class);
          if (datum != null)
          {
             res.assign(object.fromResourceId(datum));
          }

          return res;
       }

       /**
        * Bulk getter for a {@code object} extent field. All components are returned as a single
        * array of {@code object}.
        *
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        *
        * @return  An array of {@code object} representing the elements of an extent field.
        */
       protected final object<?>[] _getObject(int extent, int offset)
       {
          object<?>[] ret = new object[extent];
          for (int k = 0; k < extent; k++)
          {
             ret[k] = _getObject(offset + k);
          }

          return ret;
       }

       /**
        * Set an {@code object} value into the data at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset at which to store the given datum in the property array.
        * @param   w
        *          FWD wrapper type for the value.
        */
       protected final void _setObject(int offset, object<?> w)
       {
          Long datum = null;
          if (w != null && !w.isUnknown())
          {
             datum = object.resourceId(w);
          }

          object<?> oldValue = _getObject(offset);

          setDatum(offset, datum);

          updateObjectRefCount(oldValue, w);
       }

       /**
        * Bulk setter for a {@code object} extent field. Each components from {@code val}
        * parameter will initialize their correspondent of the extent field in {@code data} array.
        *
        * @param   val
        *          An array of {@code object} values to be used for setting the extent field.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setObject(object<?>[] val, int extent, int offset)
       {
          int len = Math.min(val.length, extent);

          for (int k = 0; k < len; k++)
          {
             _setObject(offset + k, val[k]);
          }
       }

       /**
        * Mass setter for a {@code object} extent field. All components of the extent field will
        * be set to {@code val} in {@code data} array.
        *
        * @param   val
        *          A {@code object} value to be used for setting the extent field components.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setObject(object<?> val, int extent, int offset)
       {
          for (int k = 0; k < extent; k++)
          {
             _setObject(offset + k, val);
          }
       }

       /**
        * Get an {@code raw} value for the datum at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset from which to retrieve the value from the property array.
        *
        * @return  The datum as an {@code raw}; will represent unknown value if the datum is
        *          {@code null}.
        */
       public final raw _getRaw(int offset)
       {
          checkIncomplete(offset);

          byte[] datum = (byte[]) data[offset];

          return datum != null ? new raw(datum) : raw.instantiateUnknownRaw();
       }

       /**
        * Bulk getter for a {@code raw} extent field. All components are returned as a single
        * array of {@code raw}.
        *
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        *
        * @return  An array of {@code raw} representing the elements of an extent field.
        */
       protected final raw[] _getRaw(int extent, int offset)
       {
          raw[] ret = new raw[extent];
          for (int k = 0; k < extent; k++)
          {
             ret[k] = _getRaw(offset + k);
          }

          return ret;
       }

       /**
        * Set an {@code raw} value into the data at the given offset in the property array.
        * <p>
        * This method serves as a bridge between the upper level DMO API used by business logic,
        * and the low-level data storage in the record.
        *
        * @param   offset
        *          Zero-based offset at which to store the given datum in the property array.
        * @param   w
        *          FWD wrapper type for the value.
        */
       protected final void _setRaw(int offset, BinaryData w)
       {
          byte[] datum = null;
          if (w != null && !w.isUnknown())
          {
             datum = w.getByteArray();
          }

          setDatum(offset, datum);
       }

       /**
        * Bulk setter for a {@code raw} extent field. Each components from {@code val}
        * parameter will initialize their correspondent of the extent field in {@code data} array.
        *
        * @param   val
        *          An array of {@code BinaryData} values to be used for setting the extent field.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setRaw(BinaryData[] val, int extent, int offset)
       {
          int len = Math.min(val.length, extent);

          for (int k = 0; k < len; k++)
          {
             _setRaw(offset + k, val[k]);
          }
       }

       /**
        * Mass setter for a {@code raw} extent field. All components of the extent field will
        * be set to {@code val} in {@code data} array.
        *
        * @param   val
        *          A {@code BinaryData} value to be used for setting the extent field components.
        * @param   extent
        *          The size of the extent field (the number of elements).
        * @param   offset
        *          Zero-based offset of the first element of the extent field.
        */
       protected final void _setRaw(BinaryData val, int extent, int offset)
       {
          for (int k = 0; k < extent; k++)
          {
             _setRaw(offset + k, val);
          }
       }

       /**
        * Update the object reference count.  It will decrement the old value reference and increment the new
        * value reference.
        * <p>
        * No-op by default.
        *
        * @param   oldVal
        *          The old value.
        * @param   newVal
        *          The new value.
        */
       protected void updateObjectRefCount(object<?> oldVal, object<?> newVal)
       {
       }

       /**
        * Check if the record is referenced by multiple buffers in the same time.
        *
        * @param   includeTransient
        *          Include the transient references (used by presort queries).
        *
        * @return  {@code true} if this record is loaded in more than one buffer.
        */
       public boolean isMultiplyReferenced(boolean includeTransient)
       {
          long nonTransientRefs = (references & ((1L << 32) - 1));
          long refs = includeTransient ? (references >>> 32) + nonTransientRefs : nonTransientRefs;
          return refs > 1;
       }

       /**
        * Increment the count of references to this object. While positive, this record must remain in the
        * current session's cache.
        *
        * @param   transient_
        *          {@code true} if this is a transient reference (usually from presort queries).
        *
        * @return  The record's reference count <em>after</em> being incremented.
        */
       final long incrementReferences(boolean transient_)
       {
          references = references + (transient_ ? (1L << 32) : 1);
          return references;
       }

       /**
        * Decrement the count of references to this object. While positive, this record must remain in the
        * current session's cache.
        *
        * @param   transient_
        *          {@code true} if this is a transient reference (usually from presort queries).
        *
        * @return  The record's reference count <em>after</em> being decremented.
        */
       final long decrementReferences(boolean transient_)
       {
          references = references - (transient_ ? (1L << 32) : 1);
          return references;
       }

       /**
        * Package private access to the subclass' record metadata for low level operations on this
        * record.
        *
        * @return  The metadata for the the concrete implementation of this class.
        */
       final RecordMeta _getRecordMeta()
       {
          return _recordMeta();
       }

       /**
        * Utility method used for debugging and logging.
        *
        * @param   oneLine
        *          Simplify the result to make it fit on a single line. Some details are skipped and column names.
        *
        * @return  the description of the object as configured by parameter(s).
        */
       public String toString2(boolean oneLine)
       {
          StringBuilder sb = new StringBuilder();

          RecordMeta meta = _recordMeta();
          if (oneLine)
          {
             int last = data.length;
             int start = (this instanceof TempTableRecord) ? 5 : 0;
             sb.append(meta.legacyName).append('/').append(meta.tables[0]).append(':').append(id).append(" {");
             for (int i = start; i < last; i++)
             {
                if (i > 0)
                {
                   sb.append(", ");
                }

                boolean isChar = data[i] instanceof String;
                if (isChar)
                {
                   sb.append("\"");
                }

                boolean incomplete = readFields != null && !readFields.get(i);

                sb.append(data[i] == null ? incomplete ? "n/a" : "?" : data[i]);
                if (isChar)
                {
                   sb.append("\"");
                }
             }
             sb.append('}');
          }
          else
          {
             sb.append("Record(").append(meta.legacyName).append(":").append(id).append("){\n");
             PropertyMeta[] pms = meta.getPropertyMeta(false);
             for (int i = 0; i < pms.length; i++)
             {
                if (i != 0)
                {
                   sb.append(",\n");
                }
                sb.append('\t').append(pms[i].getLegacyName()).append(": ");

                int extent = pms[i].getExtent();
                if (extent == 0)
                {
                   sb.append(data[i]);
                }
                else
                {
                   for (int k = 0; k < extent; k++)
                   {
                      sb.append(k == 0 ? "[" : "");
                      sb.append(data[i + k]);
                   }

                   i += extent - 1;
                   sb.append("]");
                }
             }

             sb.append("\n}");
          }

          return sb.toString();
       }

       /**
        * Given a map which contains legacy property names to their values, populate this record by deserializing
        * the expected value using the given function.
        *
        * @param    properties
        *           The properties for this record, which may be serialized as a Java type or as a String (in case
        *           of extents).
        * @param    f
        *           The function used to deserialize the values.  The first argument is the {@link PropertyMeta},
        *           the second argument is the property value from the <code>properties</code> map and the returned
        *           value is the deserialized value of this property, compatible with
        *           {@link PropertyMeta#getDataHandler()}.
        */
       public void setPropertyValues(Map<String, Object> properties, BiFunction<PropertyMeta, Object, Object> f)
       {
          RecordMeta recMeta = _recordMeta();
          PropertyMeta[] props = recMeta.getPropertyMeta(false);
          for (int i = 0; i < props.length; i++)
          {
             PropertyMeta prop = props[i];

             Object val = properties.get(prop.getLegacyName());
             val = f.apply(prop, val);

             if (prop.getExtent() > 0)
             {
                for (int j = 0; j < prop.getExtent(); j++, i++)
                {
                   prop = props[i];

                   BaseDataType fval = (BaseDataType) Array.get(val, j);
                   prop.getDataHandler().setField(data, fval, i, prop);
                }
             }
             else
             {
                prop.getDataHandler().setField(data, (BaseDataType) val, i, prop);
             }
          }
       }

       /**
        * Get all the properties from this record, in a map using as keys their legacy name.
        * <p>
        * Any extent properties will be contained as a Java array.
        *
        * @return   See above.
        */
       @Override
       public Map<String, Object> getPropertyValues()
       {
          Map<String, Object> res = new HashMap<>();

          RecordMeta recMeta = _recordMeta();
          PropertyMeta[] props = recMeta.getPropertyMeta(false);
          for (int i = 0; i < props.length; i++)
          {
             PropertyMeta prop = props[i];
             int extent = prop.getExtent();
             String legacyName = prop.getLegacyName();
             if (extent > 0)
             {
                Object arr = null;
                for (int j = 0; j < extent; j++, i++)
                {
                   prop = props[i];
                   BaseDataType val = prop.getDataHandler().getField(this, i);

                   if (arr == null)
                   {
                      arr = Array.newInstance(val.getClass(), extent);
                   }
                   Array.set(arr, j, val);
                }
                res.put(legacyName, arr);
                i--; // 'i' was already incremented in the main loop once
             }
             else
             {
                BaseDataType val = prop.getDataHandler().getField(this, i);
                if (!res.containsKey(legacyName))
                {
                   res.put(legacyName, val);
                }
                else
                {
                   // denormalized extent fields?
                   res.put(prop.getName(), val);
                }
             }
          }

          return res;
       }

       /**
        * Check if two {@link Record} objects are equal from the point of view of the {@code data} array.
        * <p>
        * <strong>To be noted</strong>, that this method accesses the {@code data} arrays directly without using
        * any getter. This provides faster access, however should be changed if not all fields are hydrated and
        * access is mandatory from a getter.
        *
        * @param  otherRecord
        *         The instance to compare against.
        *
        * @return True if the {@code data} arrays are equal, false - otherwise
        */
       public boolean equalData(Record otherRecord)
       {
          return Arrays.equals(this.data, otherRecord.data);
       }

       /**
        * Converts this {@code Record} into a POJO, if POJO class is available.
        * To be implemented by DMO implementations.
        *
        * @return  a POJO object with same data as current object.
        */
       public abstract Object toPOJO();

       /**
        * Populates this object with data from a POJO. This is called by {@code fromPOJO()}.
        * To be implemented by DMO implementations.
        *
        * @param   pojo
        *          The source for data.
        */
       protected abstract void populateFromPOJO(Object pojo);

       /**
        * Create a new DMO {@code Record} starting from a POJO. To work, the application must be converted with
        * POJO generation enabled.
        *
        * @param   pojo
        *          The source for the new DMO Object.
        *
        * @return  The DMO object created using data from POJO.
        */
       public static DataModelObject fromPOJO(Object pojo)
       {
          DmoMeta dmoMeta = DmoMetadataManager.byPojoClass(pojo.getClass());
          if (dmoMeta == null)
          {
             return null;
          }

          Record dmo;
          try
          {
             dmo = dmoMeta.getImplementationClass().getDeclaredConstructor().newInstance();
          }
          catch (InstantiationException | IllegalAccessException | IllegalArgumentException |
                    InvocationTargetException | NoSuchMethodException | SecurityException e)
          {
             return null;
          }

          dmo.populateFromPOJO(pojo);
          return (DataModelObject) dmo;
       }

       /**
        * Helper function to convert form a {@code java.sql.Date} to a {@code GregorianCalendar} instance.
        *
        * @param   date
        *          The {@code date} to be converted.
        *
        * @return  The converted date as a {@code GregorianCalendar} instance.
        */
       protected static GregorianCalendar toPojo(Date date)
       {
          if (date == null)
          {
             return null;
          }

          GregorianCalendar gc = new GregorianCalendar();
          gc.setTime(date);
          return gc;
       }

       /**
        * Helper function to convert form a {@code java.sql.Timestamp} to a {@code GregorianCalendar} instance.
        *
        * @param   datetime
        *          The {@code datetime} instant to be converted.
        *
        * @return  The converted date as a {@code GregorianCalendar} instance.
        */
       protected static GregorianCalendar toPojo(Timestamp datetime)
       {
          if (datetime == null)
          {
             return null;
          }

          GregorianCalendar gc = new GregorianCalendar();
          gc.setTimeInMillis(datetime.getTime());
          return gc;
       }

       /**
        * Helper function to convert form a {@code java.time.OffsetDateTime} to a {@code GregorianCalendar}
        * instance.
        *
        * @param   datetimetz
        *          The {@code datetimetz} instant to be converted.
        *
        * @return  The converted date as a {@code GregorianCalendar} instance.
        */
       protected static GregorianCalendar toPojo(OffsetDateTime datetimetz)
       {
          if (datetimetz == null)
          {
             return null;
          }

          return GregorianCalendar.from(datetimetz.toZonedDateTime());
       }

       /**
        * Helper function to convert form a {@code GregorianCalendar} to a {@code java.sql.Date} instance.
        *
        * @param   date
        *          The {@code GregorianCalendar} to be converted.
        *
        * @return  The converted date as a {@code Date} instance.
        */
       protected static Date toDmoDate(GregorianCalendar date)
       {
          if (date == null)
          {
             return null;
          }

          return new Date(date.getTime().getTime());
       }

       /**
        * Helper function to convert form a {@code GregorianCalendar} to a {@code java.sql.Timestamp} instance.
        *
        * @param   datetime
        *          The {@code GregorianCalendar} instant to be converted.
        *
        * @return  The converted date as a {@code datetime} instance.
        */
       protected static Timestamp toDmoDatetime(GregorianCalendar datetime)
       {
          if (datetime == null)
          {
             return null;
          }

          return new Timestamp(datetime.getTimeInMillis());
       }

       /**
        * Helper function to convert form a {@code GregorianCalendar} to a {@code java.time.OffsetDateTime}
        * instance.
        *
        * @param   datetimetz
        *          The {@code GregorianCalendar} instant to be converted.
        *
        * @return  The converted date as a {@code datetimetz} instance.
        */
       protected static OffsetDateTime toDmoDatetimetz(GregorianCalendar datetimetz)
       {
          if (datetimetz == null)
          {
             return null;
          }

          return datetimetz.toZonedDateTime().toOffsetDateTime();
       }
    }