SequenceManager.java

/*
** Module   : SequenceManager.java
** Abstract : Static abstract class that handles sequence functions and statements from
**            Progress / OpenEdge 10.x. The actual implementation is delegated to one of the
**            derived classes that implements a strategy of handling the persistence of the sequences.
**
** Copyright (c) 2013-2025, Golden Code Development Corporation.
**
** -#- -I- --Date-- ---------------------------------------Description---------------------------------------
** 001 OM  20121116 Created initial version.
** 002 OM  20130507 Switch to int64 API function for obtaining desired java type.
** 003 OM  20130703 Massive changes: 
**                   - Removed unneeded overloaded signatures leaving the wider form (long in
**                      place of int and int64 for integer).
**                   - Added support for legacy-to-sql name mapping.
**                   - Added error checking for invalid names and values.
**                   - getSequenceHandler() will use the P2J dialect to obtain the handler.
** 004 ECF 20150202 Lowercase legacy sequence names when using them as map keys.
** 005 ECF 20170201 Lowercase keys to sequences map.
** 006 ECF 20171201 Look up sequence by database alias as well as logical database name.
**     OM  20180126 Final look up of sequences done by database schema name.
** 007 ECF 20200610 The sequence definitions are read from annotations of _Sequence enum.
** 008 SBI 20200710 Fixed resolveDynamicName on behalf of Constantin.
** 009 OM  20220531 Added validation. Extracted common code in worker procedures.
**     CA  20220602 Ensure SQL sequence names are lowercased when used as keys.
**     CA  20220831 Ensure SQL sequence name returned by resolveDynamicName is lowercased.
**     CA  20221014 legacyMap is always populated with the legacy to SQL name of sequences - this is required
**                  because resolveDynamicName can't assume that if an entry is missing, then the SQL name
**                  must be lowercased (MariaDB dialect is case-sensitive!).
**     CA  20230116 Avoid using handle.unwrap, handle.getReference or other BDT usage from within FWD runtime.
** 010 GBB 20230512 Logging methods replaced by CentralLogger/ConversionStatus.
** 011 OM  20250110 Added sequence support for multi-tenant databases.
** 012 CA  20250321 Added overloads for DYNAMIC-CURENT-VALUE statement (dynamicSetValue).
*/

/*
** 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.*;
import java.util.*;
import java.util.logging.Level;
import com.goldencode.p2j.persist.dialect.*;
import com.goldencode.p2j.persist.orm.*;
import com.goldencode.p2j.persist.sequence.*;
import com.goldencode.p2j.util.*;
import com.goldencode.p2j.util.logging.*;

/**
 * A class that manages all sequence handling functions and statements calls,
 * including static dynamic forms. It also manages a map with handlers for each database
 * and will dispatch the primitives to a dedicate handler per database.
 * 
 * The runtime implementations of XXXSequenceHandlers the statement/functions leverage dialect
 * infrastructure in Hibernate if possible (if we find it is feasible to use native sequences
 * on PostgreSQL). If this is not possible, the SequenceHandlers will use any native support
 * the respective database server offer and will emulate the needed 4GL behavior in java.
 */
public abstract class SequenceManager
{
   /**
    * A default handler for sequences that will return unknown values.
    * It is used for sequences that are not found in db or unsupported dialects. 
    */
   private static final SequenceHandler defaultHandler = new SequenceHandler("");
   
   /**
    * The list of all known sequences in a double hashed Map (schema x sqlName). 
    * <p>
    * <i>I wonder if the first level uses the sequence names and the second 
    * the database. This makes it easier to look for a sequence when the name 
    * of the database is default/unknown. </i>
    */
   private static final HashMap<String, HashMap<String, Sequence>> sequences = new HashMap<>();
   
   /** 
    * Internal data structure with all instantiated {@link SequenceHandler}s.
    * The keys are logical database names. This assures that for each database there is only one
    * <code>SequenceHandler</code> which also serves for synchronizing access to sequence
    * functionality using these database-unique objects as locks. 
    */
   private static final HashMap<String, SequenceHandler> seqHandlers = new HashMap<>();
   
   /**
    * Mapping from 4GL-legacy names to db-oriented names used in application.
    * Each schema has its own set of mapping for sequences. This is why this member is
    * double-hashed.
    * <strong>Note:</strong>Only sequences that have mutated name will be store is this structure.
    */
   private static final HashMap<String, HashMap<String, String>> legacyMap = new HashMap<>();
   
   /** Constant used to activate the NEXT-VALUE mode. */
   private static final boolean NEXT = true;
   
   /** Constant used for obtaining the current value of the sequence. */
   private static final boolean CURRENT = false;
   
   /** Constant for forcing the auto-detection of tenant. */
   private static final Long AUTO_TENANT = null;
   
   /**
    * Maps the <code>CURRENT-VALUE(seqName)</code> function from Progress as
    * it is defined in Open Edge 10.x.
    * Returns the current value of a sequence defined in the Data
    * Dictionary.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in 4GL.
    *
    * @return
    *       The current value of a sequence can be one of the following:
    *       <ul>
    *          <li>The initial value specified in the Data Dictionary.
    *          <li>The last value set with either the
    *             <code>CURRENT-VALUE</code> statement or the 
    *             <code>NEXT-VALUE</code> function.
    *          <li>The unknown value (<code>?</code>) if the sequence has 
    *             exceeded its minimum or maximum and is not cycling.
    *       </ul>
    */
   public static int64 currentValue(String seqName)
   {
      return getValueImpl(CURRENT, null, seqName, false, AUTO_TENANT);
   }
   
   /**
    * Maps the <code>CURRENT-VALUE(seqName)</code> function from Progress as
    * it is defined in Open Edge 10.x.
    * Returns the current value of a sequence defined in the Data
    * Dictionary.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in 4GL.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    *
    * @return
    *       The current value of a sequence can be one of the following:
    *       <ul>
    *          <li>The initial value specified in the Data Dictionary.
    *          <li>The last value set with either the
    *             <code>CURRENT-VALUE</code> statement or the 
    *             <code>NEXT-VALUE</code> function.
    *          <li>The unknown value (<code>?</code>) if the sequence has 
    *             exceeded its minimum or maximum and is not cycling.
    *       </ul>
    */
   public static int64 currentValue(String seqName, NumberType tenantId)
   {
      Long tenant = tenantId == null || tenantId.isUnknown() ? null : tenantId.longValue();
      return getValueImpl(CURRENT, null, seqName, false, tenant);
   }
   
   /**
    * Maps the <code>CURRENT-VALUE(seqName)</code> function from Progress as
    * it is defined in Open Edge 10.x.
    * Returns the current value of a sequence defined in the Data
    * Dictionary.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in 4GL.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    *
    * @return
    *       The current value of a sequence can be one of the following:
    *       <ul>
    *          <li>The initial value specified in the Data Dictionary.
    *          <li>The last value set with either the
    *             <code>CURRENT-VALUE</code> statement or the 
    *             <code>NEXT-VALUE</code> function.
    *          <li>The unknown value (<code>?</code>) if the sequence has 
    *             exceeded its minimum or maximum and is not cycling.
    *       </ul>
    */
   public static int64 currentValue(String seqName, long tenantId)
   {
      return getValueImpl(CURRENT, null, seqName, false, tenantId);
   }
   
   /**
    * Maps the <code>CURRENT-VALUE(seqName, ldbName)</code> function from 
    * Progress as it is defined in Open Edge 10.x.
    * Returns the current value of the sequence defined in 4GL.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param ldbName
    *          An identifier that specifies the logical name of the database
    *          in which the sequence is defined. The database must be
    *          connected. You can omit this parameter if the sequence name is
    *          unambiguous. If a sequence with this name exists in more than
    *          one connected database, then you must specify
    *          <code>ldbName</code>.
    *
    * @return
    *       The current value of a sequence can be one of the following:
    *       <ul>
    *          <li>The initial value specified in the Data Dictionary.
    *          <li>The last value set with either the
    *             <code>CURRENT-VALUE</code> statement or the 
    *             <code>NEXT-VALUE</code> function.
    *          <li>The unknown value (<code>?</code>) if the sequence has 
    *             exceeded its minimum or maximum and is not cycling.
    *       </ul>
    */
   public static int64 currentValue(String seqName, String ldbName)
   {
      return getValueImpl(CURRENT, ldbName, seqName, false, AUTO_TENANT);
   }
   
   /**
    * Maps the {@code CURRENT-VALUE(seqName, ldbName)} function from Progress as it is defined in Open
    * Edge 10.x. Returns the current value of the sequence defined in 4GL.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          An identifier that specifies the logical name of the database in which the sequence is defined.
    *          The database must be connected. You can omit this parameter if the sequence name is
    *          unambiguous. If a sequence with this name exists in more than one connected database, then you
    *          must specify {@code ldbName}.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    *
    * @return
    *       The current value of a sequence can be one of the following:
    *       <ul>
    *          <li>The initial value specified in the Data Dictionary.
    *          <li>The last value set with either the
    *             <code>CURRENT-VALUE</code> statement or the 
    *             <code>NEXT-VALUE</code> function.
    *          <li>The unknown value (<code>?</code>) if the sequence has 
    *             exceeded its minimum or maximum and is not cycling.
    *       </ul>
    */
   public static int64 currentValue(String seqName, String ldbName, NumberType tenantId)
   {
      Long tenant = tenantId == null || tenantId.isUnknown() ? null : tenantId.longValue();
      return getValueImpl(CURRENT, ldbName, seqName, false, tenant);
   }
   
   /**
    * Maps the {@code CURRENT-VALUE(seqName, ldbName)} function from Progress as it is defined in Open
    * Edge 10.x. Returns the current value of the sequence defined in 4GL.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          An identifier that specifies the logical name of the database in which the sequence is defined.
    *          The database must be connected. You can omit this parameter if the sequence name is
    *          unambiguous. If a sequence with this name exists in more than one connected database, then you
    *          must specify {@code ldbName}.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    *
    * @return
    *       The current value of a sequence can be one of the following:
    *       <ul>
    *          <li>The initial value specified in the Data Dictionary.
    *          <li>The last value set with either the
    *             <code>CURRENT-VALUE</code> statement or the 
    *             <code>NEXT-VALUE</code> function.
    *          <li>The unknown value (<code>?</code>) if the sequence has 
    *             exceeded its minimum or maximum and is not cycling.
    *       </ul>
    */
   public static int64 currentValue(String seqName, String ldbName, long tenantId)
   {
      return getValueImpl(CURRENT, ldbName, seqName, false, tenantId);
   }
   
   /**
    * Maps the <code>NEXT-VALUE(seqName)</code> function from Progress as it is defined in Open Edge 10.x.
    * Returns the next value of the sequence, incremented by the
    * positive or negative value defined in the Data Dictionary.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    *
    * @return
    *       The next value of a sequence can be one of the following:
    *       <ul>
    *          <li>The value obtained by incremented the current value of the 
    *             sequence with its increment if the value does not cross the
    *             upper/lower limits. In the case of cycling sequences the
    *             sequence value is reset to initial value. 
    *          <li>The unknown value (<code>?</code>) if the sequence has 
    *             exceeded its minimum or maximum and is not cycling.
    *       </ul>
    */
   public static int64 nextValue(String seqName)
   {
      return getValueImpl(NEXT, null, seqName, false, AUTO_TENANT);
   }
   
   /**
    * Maps the <code>NEXT-VALUE(seqName)</code> function from Progress as it is defined in Open Edge 10.x.
    * Returns the next value of the sequence, incremented by the
    * positive or negative value defined in the Data Dictionary.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    *
    * @return
    *       The next value of a sequence can be one of the following:
    *       <ul>
    *          <li>The value obtained by incremented the current value of the 
    *             sequence with its increment if the value does not cross the
    *             upper/lower limits. In the case of cycling sequences the
    *             sequence value is reset to initial value. 
    *          <li>The unknown value (<code>?</code>) if the sequence has 
    *             exceeded its minimum or maximum and is not cycling.
    *       </ul>
    */
   public static int64 nextValue(String seqName, long tenantId)
   {
      return getValueImpl(NEXT, null, seqName, false, tenantId);
   }
   
   /**
    * Maps the {@code NEXT-VALUE(seqName, ldbName)} function from Progress as it is defined in Open Edge 10.x.
    * Returns the next value of the sequence, incremented by the
    * positive or negative value defined in the Data Dictionary.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          An identifier that specifies the logical name of the database
    *          in which the sequence is defined. The database must be
    *          connected. If multiple databases are connected, you can omit
    *          this parameter if you specify a sequence that is unique to
    *          one of the databases.
    *
    * @return
    *       The next value of a sequence can be one of the following:
    *       <ul>
    *          <li>The initial value specified in the Data Dictionary.
    *          <li>The last value set with either the
    *             <code>CURRENT-VALUE</code> statement or the 
    *             <code>NEXT-VALUE</code> function.
    *          <li>The unknown value (<code>?</code>) if the sequence has 
    *             exceeded its minimum or maximum and is not cycling.
    *       </ul>
    */
   public static int64 nextValue(String seqName, String ldbName)
   {
      return getValueImpl(NEXT, ldbName, seqName, false, AUTO_TENANT);
   }
   
   /**
    * Maps the {@code NEXT-VALUE(seqName, ldbName)} function from Progress as it is defined in Open Edge 10.x.
    * Returns the next value of the sequence, incremented by the
    * positive or negative value defined in the Data Dictionary.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          An identifier that specifies the logical name of the database
    *          in which the sequence is defined. The database must be
    *          connected. If multiple databases are connected, you can omit
    *          this parameter if you specify a sequence that is unique to
    *          one of the databases.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    *
    * @return
    *       The next value of a sequence can be one of the following:
    *       <ul>
    *          <li>The initial value specified in the Data Dictionary.
    *          <li>The last value set with either the
    *             <code>CURRENT-VALUE</code> statement or the 
    *             <code>NEXT-VALUE</code> function.
    *          <li>The unknown value (<code>?</code>) if the sequence has 
    *             exceeded its minimum or maximum and is not cycling.
    *       </ul>
    */
   public static int64 nextValue(String seqName, String ldbName, NumberType tenantId)
   {
      Long tenant = tenantId == null || tenantId.isUnknown() ? null : tenantId.longValue();
      return getValueImpl(NEXT, ldbName, seqName, false, tenant);
   }
   
   /**
    * Maps the {@code NEXT-VALUE(seqName, ldbName)} function from Progress as it is defined in Open Edge 10.x.
    * Returns the next value of the sequence, incremented by the
    * positive or negative value defined in the Data Dictionary.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    *
    * @return
    *       The next value of a sequence can be one of the following:
    *       <ul>
    *          <li>The initial value specified in the Data Dictionary.
    *          <li>The last value set with either the
    *             <code>CURRENT-VALUE</code> statement or the 
    *             <code>NEXT-VALUE</code> function.
    *          <li>The unknown value (<code>?</code>) if the sequence has 
    *             exceeded its minimum or maximum and is not cycling.
    *       </ul>
    */
   public static int64 nextValue(String seqName, NumberType tenantId)
   {
      Long tenant = tenantId == null || tenantId.isUnknown() ? null : tenantId.longValue();
      return getValueImpl(NEXT, null, seqName, false, tenant);
   }
   
   /**
    * Maps the {@code NEXT-VALUE(seqName, ldbName)} function from Progress as it is defined in Open Edge 10.x.
    * Returns the next value of the sequence, incremented by the
    * positive or negative value defined in the Data Dictionary.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          An identifier that specifies the logical name of the database
    *          in which the sequence is defined. The database must be
    *          connected. If multiple databases are connected, you can omit
    *          this parameter if you specify a sequence that is unique to
    *          one of the databases.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    *
    * @return
    *       The next value of a sequence can be one of the following:
    *       <ul>
    *          <li>The initial value specified in the Data Dictionary.
    *          <li>The last value set with either the
    *             <code>CURRENT-VALUE</code> statement or the 
    *             <code>NEXT-VALUE</code> function.
    *          <li>The unknown value (<code>?</code>) if the sequence has 
    *             exceeded its minimum or maximum and is not cycling.
    *       </ul>
    */
   public static int64 nextValue(String seqName, String ldbName, long tenantId)
   {
      return getValueImpl(NEXT, ldbName, seqName, false, tenantId);
   }
   
   /**
    * Maps the <code>DYNAMIC-CURRENT-VALUE(seqName, ldbName)</code> function
    * from Progress as it is defined in Open Edge 10.x.
    * Returns the current value of the sequence defined in the Data Dictionary.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          The logical name of the database in which the sequence is 
    *          defined. The database must be connected.
    *
    * @return
    *       The current value of a sequence can be one of the following:
    *       <ul>
    *          <li>The initial value specified in the Data Dictionary.
    *          <li>The last value set with either the
    *             <code>CURRENT-VALUE</code> statement or the 
    *             <code>NEXT-VALUE</code> function.
    *          <li>The unknown value (<code>?</code>) if the sequence has 
    *             exceeded its minimum or maximum and is not cycling.
    *       </ul>
    */
   public static int64 dynamicCurrentValue(String seqName, String ldbName)
   {
      return getValueImpl(CURRENT, ldbName, seqName, true, AUTO_TENANT);
   }
   
   /**
    * Maps the <code>DYNAMIC-CURRENT-VALUE(seqName, ldbName)</code> function from Progress as it is defined in
    * Open Edge 10.x.
    * Returns the current value of the sequence defined in the Data Dictionary.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          The logical name of the database in which the sequence is 
    *          defined. The database must be connected.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    *
    * @return
    *       The current value of a sequence can be one of the following:
    *       <ul>
    *          <li>The initial value specified in the Data Dictionary.
    *          <li>The last value set with either the
    *             <code>CURRENT-VALUE</code> statement or the 
    *             <code>NEXT-VALUE</code> function.
    *          <li>The unknown value (<code>?</code>) if the sequence has 
    *             exceeded its minimum or maximum and is not cycling.
    *       </ul>
    */
   public static int64 dynamicCurrentValue(String seqName, String ldbName, NumberType tenantId)
   {
      Long tenant = tenantId == null || tenantId.isUnknown() ? null : tenantId.longValue();
      return getValueImpl(CURRENT, ldbName, seqName, true, tenant);
   }
   
   /**
    * Maps the <code>DYNAMIC-CURRENT-VALUE(seqName, ldbName)</code> function
    * from Progress as it is defined in Open Edge 10.x.
    * Returns the current value of the sequence defined in the Data Dictionary.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          The logical name of the database in which the sequence is 
    *          defined. The database must be connected.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    *
    * @return
    *       The current value of a sequence can be one of the following:
    *       <ul>
    *          <li>The initial value specified in the Data Dictionary.
    *          <li>The last value set with either the
    *             <code>CURRENT-VALUE</code> statement or the 
    *             <code>NEXT-VALUE</code> function.
    *          <li>The unknown value (<code>?</code>) if the sequence has 
    *             exceeded its minimum or maximum and is not cycling.
    *       </ul>
    */
   public static int64 dynamicCurrentValue(String seqName, String ldbName, long tenantId)
   {
      return getValueImpl(CURRENT, ldbName, seqName, true, tenantId);
   }
   
   /**
    * Maps the <code>DYNAMIC-CURRENT-VALUE(seqName, ldbName)</code> function
    * from Progress as it is defined in Open Edge 10.x.
    * Returns the current value of the sequence defined in the Data Dictionary.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          A character expression that evaluates to a logical name of 
    *          the database in which the sequence is defined. The database must be connected.
    *
    * @return
    *       The current value of a sequence can be one of the following:
    *       <ul>
    *          <li>The initial value specified in the Data Dictionary.
    *          <li>The last value set with either the
    *             <code>CURRENT-VALUE</code> statement or the 
    *             <code>NEXT-VALUE</code> function.
    *          <li>The unknown value (<code>?</code>) if the sequence has 
    *             exceeded its minimum or maximum and is not cycling.
    *       </ul>
    */
   public static int64 dynamicCurrentValue(String seqName, character ldbName)
   {
      return getValueImpl(CURRENT, ldbName.toJavaType(), seqName, true, AUTO_TENANT);
   }
   
   /**
    * Maps the <code>DYNAMIC-CURRENT-VALUE(seqName, ldbName)</code> function
    * from Progress as it is defined in Open Edge 10.x.
    * Returns the current value of the sequence defined in the Data Dictionary.
    *
    * @param   seqName
    *          A character expression that evaluates to the legacy name of a sequence defined in the
    *          Data Dictionary.
    * @param   ldbName
    *          The logical name of the database in which the sequence is 
    *          defined. The database must be connected.
    *
    * @return
    *       The current value of a sequence can be one of the following:
    *       <ul>
    *          <li>The initial value specified in the Data Dictionary.
    *          <li>The last value set with either the
    *             <code>CURRENT-VALUE</code> statement or the 
    *             <code>NEXT-VALUE</code> function.
    *          <li>The unknown value (<code>?</code>) if the sequence has 
    *             exceeded its minimum or maximum and is not cycling.
    *       </ul>
    */
   public static int64 dynamicCurrentValue(character seqName, String ldbName)
   {
      return getValueImpl(CURRENT, ldbName, seqName.toJavaType(), true, AUTO_TENANT);
   }
   
   /**
    * Maps the <code>DYNAMIC-CURRENT-VALUE(seqName, ldbName)</code> function
    * from Progress as it is defined in Open Edge 10.x.
    * Returns the current value of the sequence defined in the Data Dictionary.
    *
    * @param   seqName
    *          A character expression that evaluates to the legacy name of a sequence defined in the Data
    *          Dictionary.
    * @param ldbName
    *          A character expression that evaluates to a logical name of
    *          the database in which the sequence is defined. The database
    *          must be connected.
    *
    * @return
    *       The current value of a sequence can be one of the following:
    *       <ul>
    *          <li>The initial value specified in the Data Dictionary.
    *          <li>The last value set with either the
    *             <code>CURRENT-VALUE</code> statement or the 
    *             <code>NEXT-VALUE</code> function.
    *          <li>The unknown value (<code>?</code>) if the sequence has 
    *             exceeded its minimum or maximum and is not cycling.
    *       </ul>
    */
   public static int64 dynamicCurrentValue(character seqName, character ldbName)
   {
      return getValueImpl(CURRENT, ldbName.toJavaType(), seqName.toJavaType(), true, AUTO_TENANT);
   }
   
   /**
    * Maps the <code>DYNAMIC-NEXT-VALUE(seqName, ldbName)</code> function
    * from Progress as it is defined in Open Edge 10.x.
    * Returns the next value of the sequence, incremented by the
    * positive or negative value defined in the Data Dictionary.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          The logical name of the database in which the sequence is 
    *          defined. The database must be connected.
    *
    * @return
    *       The next value of a sequence can be one of the following:
    *       <ul>
    *          <li>The value obtained by incremented the current value of the 
    *             sequence with its increment if the value does not cross the
    *             upper/lower limits. In the case of cycling sequences the
    *             sequence value is reset to initial value. 
    *          <li>The unknown value (<code>?</code>) if the sequence has 
    *             exceeded its minimum or maximum and is not cycling.
    *       </ul>
    */
   public static int64 dynamicNextValue(String seqName, String ldbName)
   {
      return getValueImpl(NEXT, ldbName, seqName, true, AUTO_TENANT);
   }
   
   /**
    * Maps the <code>DYNAMIC-NEXT-VALUE(seqName, ldbName)</code> function
    * from Progress as it is defined in Open Edge 10.x.
    * Returns the next value of the sequence, incremented by the
    * positive or negative value defined in the Data Dictionary.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          The logical name of the database in which the sequence is 
    *          defined. The database must be connected.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    *
    * @return
    *       The next value of a sequence can be one of the following:
    *       <ul>
    *          <li>The value obtained by incremented the current value of the 
    *             sequence with its increment if the value does not cross the
    *             upper/lower limits. In the case of cycling sequences the
    *             sequence value is reset to initial value. 
    *          <li>The unknown value (<code>?</code>) if the sequence has 
    *             exceeded its minimum or maximum and is not cycling.
    *       </ul>
    */
   public static int64 dynamicNextValue(String seqName, String ldbName, NumberType tenantId)
   {
      Long tenant = tenantId == null || tenantId.isUnknown() ? null : tenantId.longValue();
      return getValueImpl(NEXT, ldbName, seqName, true, tenant);
   }
   
   /**
    * Maps the <code>DYNAMIC-NEXT-VALUE(seqName, ldbName)</code> function
    * from Progress as it is defined in Open Edge 10.x.
    * Returns the next value of the sequence, incremented by the
    * positive or negative value defined in the Data Dictionary.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          The logical name of the database in which the sequence is 
    *          defined. The database must be connected.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    *
    * @return
    *       The next value of a sequence can be one of the following:
    *       <ul>
    *          <li>The value obtained by incremented the current value of the 
    *             sequence with its increment if the value does not cross the
    *             upper/lower limits. In the case of cycling sequences the
    *             sequence value is reset to initial value. 
    *          <li>The unknown value (<code>?</code>) if the sequence has 
    *             exceeded its minimum or maximum and is not cycling.
    *       </ul>
    */
   public static int64 dynamicNextValue(String seqName, String ldbName, long tenantId)
   {
      return getValueImpl(NEXT, ldbName, seqName, true, tenantId);
   }
   
   /**
    * Maps the <code>DYNAMIC-NEXT-VALUE(seqName, ldbName)</code> function
    * from Progress as it is defined in Open Edge 10.x.
    * Returns the next value of the sequence, incremented by the
    * positive or negative value defined in the Data Dictionary.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          A character expression that evaluates to a logical name of
    *          the database in which the sequence is defined. The database
    *          must be connected.
    *
    * @return
    *       The next value of a sequence can be one of the following:
    *       <ul>
    *          <li>The value obtained by incremented the current value of the 
    *             sequence with its increment if the value does not cross the
    *             upper/lower limits. In the case of cycling sequences the
    *             sequence value is reset to initial value.
    *          <li>The unknown value (<code>?</code>) if the sequence has 
    *             exceeded its minimum or maximum and is not cycling.
    *       </ul>
    */
   public static int64 dynamicNextValue(String seqName, character ldbName)
   {
      return getValueImpl(NEXT, ldbName.toJavaType(), seqName, true, AUTO_TENANT);
   }
   
   /**
    * Maps the <code>DYNAMIC-NEXT-VALUE(seqName, ldbName)</code> function
    * from Progress as it is defined in Open Edge 10.x.
    * Returns the next value of the sequence, incremented by the
    * positive or negative value defined in the Data Dictionary.
    *
    * @param   seqName
    *          A character expression that evaluates to the legacy name of a sequence defined in the Data
    *          Dictionary.
    * @param   ldbName
    *          The logical name of the database in which the sequence is 
    *          defined. The database must be connected.
    *
    * @return
    *       The next value of a sequence can be one of the following:
    *       <ul>
    *          <li>The value obtained by incremented the current value of the 
    *             sequence with its increment if the value does not cross the
    *             upper/lower limits. In the case of cycling sequences the
    *             sequence value is reset to initial value.
    *          <li>The unknown value (<code>?</code>) if the sequence has 
    *             exceeded its minimum or maximum and is not cycling.
    *       </ul>
    */
   public static int64 dynamicNextValue(character seqName, String ldbName)
   {
      return getValueImpl(NEXT, ldbName, seqName.toJavaType(), true, AUTO_TENANT);
   }
   
   /**
    * Maps the <code>DYNAMIC-NEXT-VALUE(seqName, ldbName)</code> function
    * from Progress as it is defined in Open Edge 10.x.
    * Returns the next value of the sequence, incremented by the
    * positive or negative value defined in the Data Dictionary.
    *
    * @param   seqName
    *          A character expression that evaluates to the legacy name of a sequence defined in the Data
    *          Dictionary.
    * @param ldbName
    *          A character expression that evaluates to a logical name of
    *          the database in which the sequence is defined. The database
    *          must be connected.
    *
    * @return
    *       The next value of a sequence can be one of the following:
    *       <ul>
    *          <li>The value obtained by incremented the current value of the 
    *             sequence with its increment if the value does not cross the
    *             upper/lower limits. In the case of cycling sequences the
    *             sequence value is reset to initial value.
    *          <li>The unknown value (<code>?</code>) if the sequence has 
    *             exceeded its minimum or maximum and is not cycling.
    *       </ul>
    */
   public static int64 dynamicNextValue(character seqName, character ldbName)
   {
      return getValueImpl(NEXT, ldbName.toJavaType(), seqName.toJavaType(), true, AUTO_TENANT);
   }
   
   /**
    * Maps the <code>CURRENT-VALUE(seqName) = expr</code> statement from
    * Progress as it is defined in Open Edge 10.x.
    * Resets the current value of the sequence to the one specified as parameter.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   newValue
    *          A numerical expression assigned as the current value of the
    *          specified sequence. If expression is outside the boundary set
    *          by the initial value (at one end) and the lower limit or upper
    *          limit (at the other end) for the sequence, Progress returns an
    *          error, and the sequence value remains unchanged.
    */
   public static void setValue(String seqName, NumberType newValue)
   {
      setValueImpl(null, seqName, newValue.isUnknown() ? null : newValue.longValue(), false, AUTO_TENANT);
   }
   
   /**
    * Maps the <code>CURRENT-VALUE(seqName) = expr</code> statement from
    * Progress as it is defined in Open Edge 10.x.
    * Resets the current value of the sequence to the one specified as parameter.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   newValue
    *          A numerical expression assigned as the current value of the
    *          specified sequence. If expression is outside the boundary set
    *          by the initial value (at one end) and the lower limit or upper
    *          limit (at the other end) for the sequence, Progress returns an
    *          error, and the sequence value remains unchanged.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    */
   public static void setValue(String seqName, NumberType newValue, long tenantId)
   {
      setValueImpl(null, seqName, newValue.isUnknown() ? null : newValue.longValue(), false, tenantId);
   }
   
   /**
    * Maps the <code>CURRENT-VALUE(seqName) = expr</code> statement from
    * Progress as it is defined in Open Edge 10.x.
    * Resets the current value of the sequence to the one specified as parameter.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   newValue
    *          An integer expression assigned as the current value of the specified sequence. If expression is
    *          outside the boundary set by the initial value (at one end) and the lower limit or upper limit
    *          (at the other end) for the sequence, FWD returns an error, and the sequence value remains
    *          unchanged.
    */
   public static void setValue(String seqName, long newValue)
   {
      setValueImpl(null, seqName, newValue, false, AUTO_TENANT);
   }
   
   /**
    * Maps the <code>CURRENT-VALUE(seqName) = expr</code> statement from
    * Progress as it is defined in Open Edge 10.x.
    * Resets the current value of the sequence to the one specified as parameter.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   newValue
    *          An integer expression assigned as the current value of the specified sequence. If expression is
    *          outside the boundary set by the initial value (at one end) and the lower limit or upper limit
    *          (at the other end) for the sequence, FWD returns an error, and the sequence value remains
    *          unchanged.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    */
   public static void setValue(String seqName, long newValue, long tenantId)
   {
      setValueImpl(null, seqName, newValue, false, tenantId);
   }
   
   /**
    * Maps the <code>CURRENT-VALUE(seqName, ldbName) = expr</code> statement
    * from Progress as it is defined in Open Edge 10.x.
    * Resets the current value of the sequence to the one specified as parameter.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          An identifier that specifies the logical name of the database
    *          in which the sequence is defined. The database must be
    *          connected. You can omit this parameter if the sequence name is
    *          unambiguous. If more than one connected database has a sequence
    *          with given name, then you must supply <code>ldbName</code>.
    * @param   newValue
    *          An integer expression assigned as the current value of the
    *          specified sequence. If expression is outside the boundary set
    *          by the initial value (at one end) and the lower limit or upper
    *          limit (at the other end) for the sequence, Progress returns an
    *          error, and the sequence value remains unchanged.
    */
   public static void setValue(String seqName, long newValue, String ldbName)
   {
      setValueImpl(ldbName, seqName, newValue, false, AUTO_TENANT);
   }
   
   /**
    * Maps the <code>CURRENT-VALUE(seqName, ldbName) = expr</code> statement
    * from Progress as it is defined in Open Edge 10.x.
    * Resets the current value of the sequence to the one specified as parameter.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          An identifier that specifies the logical name of the database
    *          in which the sequence is defined. The database must be
    *          connected. You can omit this parameter if the sequence name is
    *          unambiguous. If more than one connected database has a sequence
    *          with given name, then you must supply <code>ldbName</code>.
    * @param   newValue
    *          An integer expression assigned as the current value of the
    *          specified sequence. If expression is outside the boundary set
    *          by the initial value (at one end) and the lower limit or upper
    *          limit (at the other end) for the sequence, Progress returns an
    *          error, and the sequence value remains unchanged.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    */
   public static void setValue(String seqName, long newValue, String ldbName, NumberType tenantId)
   {
      Long tenant = tenantId == null || tenantId.isUnknown() ? null : tenantId.longValue();
      setValueImpl(ldbName, seqName, newValue, false, tenant);
   }
   
   /**
    * Maps the <code>CURRENT-VALUE(seqName, ldbName) = expr</code> statement
    * from Progress as it is defined in Open Edge 10.x.
    * Resets the current value of the sequence to the one specified as parameter.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   newValue
    *          An integer expression assigned as the current value of the
    *          specified sequence. If expression is outside the boundary set
    *          by the initial value (at one end) and the lower limit or upper
    *          limit (at the other end) for the sequence, Progress returns an
    *          error, and the sequence value remains unchanged.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    */
   public static void setValue(String seqName, long newValue, NumberType tenantId)
   {
      Long tenant = tenantId == null || tenantId.isUnknown() ? null : tenantId.longValue();
      setValueImpl(null, seqName, newValue, false, tenant);
   }
   
   /**
    * Maps the <code>CURRENT-VALUE(seqName, ldbName) = expr</code> statement
    * from Progress as it is defined in Open Edge 10.x.
    * Resets the current value of the sequence to the one specified as parameter.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          An identifier that specifies the logical name of the database
    *          in which the sequence is defined. The database must be
    *          connected. You can omit this parameter if the sequence name is
    *          unambiguous. If more than one connected database has a sequence
    *          with given name, then you must supply <code>ldbName</code>.
    * @param   newValue
    *          An integer expression assigned as the current value of the
    *          specified sequence. If expression is outside the boundary set
    *          by the initial value (at one end) and the lower limit or upper
    *          limit (at the other end) for the sequence, Progress returns an
    *          error, and the sequence value remains unchanged.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    */
   public static void setValue(String seqName, long newValue, String ldbName, long tenantId)
   {
      setValueImpl(ldbName, seqName, newValue, false, tenantId);
   }
   
   /**
    * Maps the <code>CURRENT-VALUE(seqName, ldbName) = expr</code> statement
    * from Progress as it is defined in Open Edge 10.x.
    * Resets the current value of the sequence to the one specified as parameter.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          An identifier that specifies the logical name of the database
    *          in which the sequence is defined. The database must be
    *          connected. You can omit this parameter if the sequence name is
    *          unambiguous. If more than one connected database has a sequence
    *          with given name, then you must supply <code>ldbName</code>.
    * @param   newValue
    *          A numerical expression assigned as the current value of the
    *          specified sequence. If expression is outside the boundary set
    *          by the initial value (at one end) and the lower limit or upper
    *          limit (at the other end) for the sequence, Progress returns an
    *          error, and the sequence value remains unchanged.
    */
   public static void setValue(String seqName, NumberType newValue, String ldbName)
   {
      setValueImpl(ldbName, seqName, newValue.isUnknown() ? null : newValue.longValue(), false, AUTO_TENANT);
   }
   
   /**
    * Maps the <code>CURRENT-VALUE(seqName, ldbName) = expr</code> statement
    * from Progress as it is defined in Open Edge 10.x.
    * Resets the current value of the sequence to the one specified as parameter.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          An identifier that specifies the logical name of the database
    *          in which the sequence is defined. The database must be
    *          connected. You can omit this parameter if the sequence name is
    *          unambiguous. If more than one connected database has a sequence
    *          with given name, then you must supply <code>ldbName</code>.
    * @param   newValue
    *          A numerical expression assigned as the current value of the
    *          specified sequence. If expression is outside the boundary set
    *          by the initial value (at one end) and the lower limit or upper
    *          limit (at the other end) for the sequence, Progress returns an
    *          error, and the sequence value remains unchanged.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    */
   public static void setValue(String seqName, NumberType newValue, String ldbName, NumberType tenantId)
   {
      Long tenant = tenantId == null || tenantId.isUnknown() ? null : tenantId.longValue();
      setValueImpl(ldbName, seqName, newValue.isUnknown() ? null : newValue.longValue(), false, tenant);
   }
   
   /**
    * Maps the <code>CURRENT-VALUE(seqName, ldbName) = expr</code> statement
    * from Progress as it is defined in Open Edge 10.x.
    * Resets the current value of the sequence to the one specified as parameter.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   newValue
    *          A numerical expression assigned as the current value of the
    *          specified sequence. If expression is outside the boundary set
    *          by the initial value (at one end) and the lower limit or upper
    *          limit (at the other end) for the sequence, Progress returns an
    *          error, and the sequence value remains unchanged.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    */
   public static void setValue(String seqName, NumberType newValue, NumberType tenantId)
   {
      Long tenant = tenantId == null || tenantId.isUnknown() ? null : tenantId.longValue();
      setValueImpl(null, seqName, newValue.isUnknown() ? null : newValue.longValue(), false, tenant);
   }
   
   /**
    * Maps the <code>CURRENT-VALUE(seqName, ldbName) = expr</code> statement
    * from Progress as it is defined in Open Edge 10.x.
    * Resets the current value of the sequence to the one specified as parameter.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          An identifier that specifies the logical name of the database
    *          in which the sequence is defined. The database must be
    *          connected. You can omit this parameter if the sequence name is
    *          unambiguous. If more than one connected database has a sequence
    *          with given name, then you must supply <code>ldbName</code>.
    * @param   newValue
    *          A numerical expression assigned as the current value of the
    *          specified sequence. If expression is outside the boundary set
    *          by the initial value (at one end) and the lower limit or upper
    *          limit (at the other end) for the sequence, Progress returns an
    *          error, and the sequence value remains unchanged.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    */
   public static void setValue(String seqName, NumberType newValue, String ldbName, long tenantId)
   {
      setValueImpl(ldbName, seqName, newValue.isUnknown() ? null : newValue.longValue(), false, tenantId);
   }
   
   /**
    * Maps the <code>DYNAMIC-CURRENT-VALUE(seqName, ldbName) = expr</code> 
    * statement from Progress as it is defined in Open Edge 10.x.
    * Resets the current value of the sequence to the one specified as parameter.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          An identifier that specifies the logical name of the database
    *          in which the sequence is defined. The database must be
    *          connected. You can omit this parameter if the sequence name is
    *          unambiguous. If more than one connected database has a sequence
    *          with given name, then you must supply <code>ldbName</code>.
    * @param   newValue
    *          An integer expression assigned as the current value of the
    *          specified sequence. If expression is outside the boundary set
    *          by the initial value (at one end) and the lower limit or upper
    *          limit (at the other end) for the sequence, Progress returns an
    *          error, and the sequence value remains unchanged.
    */
   public static void dynamicSetValue(String seqName, long newValue, String ldbName)
   {
      setValueImpl(ldbName, seqName, newValue, true, AUTO_TENANT);
   }
   
   /**
    * Maps the <code>DYNAMIC-CURRENT-VALUE(seqName, ldbName) = expr</code> 
    * statement from Progress as it is defined in Open Edge 10.x.
    * Resets the current value of the sequence to the one specified as parameter.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          An identifier that specifies the logical name of the database
    *          in which the sequence is defined. The database must be
    *          connected. You can omit this parameter if the sequence name is
    *          unambiguous. If more than one connected database has a sequence
    *          with given name, then you must supply <code>ldbName</code>.
    * @param   newValue
    *          An integer expression assigned as the current value of the
    *          specified sequence. If expression is outside the boundary set
    *          by the initial value (at one end) and the lower limit or upper
    *          limit (at the other end) for the sequence, Progress returns an
    *          error, and the sequence value remains unchanged.
    */
   public static void dynamicSetValue(String seqName, NumberType newValue, String ldbName)
   {
      setValueImpl(ldbName, seqName, newValue.isUnknown() ? null : newValue.longValue(), true, AUTO_TENANT);
   }
   
   /**
    * Maps the <code>DYNAMIC-CURRENT-VALUE(seqName, ldbName) = expr</code> 
    * statement from Progress as it is defined in Open Edge 10.x.
    * Resets the current value of the sequence to the one specified as parameter.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          An identifier that specifies the logical name of the database
    *          in which the sequence is defined. The database must be
    *          connected. You can omit this parameter if the sequence name is
    *          unambiguous. If more than one connected database has a sequence
    *          with given name, then you must supply <code>ldbName</code>.
    * @param   newValue
    *          An integer expression assigned as the current value of the
    *          specified sequence. If expression is outside the boundary set
    *          by the initial value (at one end) and the lower limit or upper
    *          limit (at the other end) for the sequence, Progress returns an
    *          error, and the sequence value remains unchanged.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    */
   public static void dynamicSetValue(String seqName, long newValue, String ldbName, NumberType tenantId)
   {
      Long tenant = tenantId == null || tenantId.isUnknown() ? null : tenantId.longValue();
      setValueImpl(ldbName, seqName, newValue, true, tenant);
   }
   
   /**
    * Maps the <code>DYNAMIC-CURRENT-VALUE(seqName, ldbName) = expr</code> 
    * statement from Progress as it is defined in Open Edge 10.x.
    * Resets the current value of the sequence to the one specified as parameter.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          An identifier that specifies the logical name of the database
    *          in which the sequence is defined. The database must be
    *          connected. You can omit this parameter if the sequence name is
    *          unambiguous. If more than one connected database has a sequence
    *          with given name, then you must supply <code>ldbName</code>.
    * @param   newValue
    *          An integer expression assigned as the current value of the
    *          specified sequence. If expression is outside the boundary set
    *          by the initial value (at one end) and the lower limit or upper
    *          limit (at the other end) for the sequence, Progress returns an
    *          error, and the sequence value remains unchanged.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    */
   public static void dynamicSetValue(String seqName, long newValue, String ldbName, long tenantId)
   {
      setValueImpl(ldbName, seqName, newValue, true, tenantId);
   }
   
   /**
    * Maps the <code>DYNAMIC-CURRENT-VALUE(seqName, ldbName) = expr</code> 
    * statement from Progress as it is defined in Open Edge 10.x.
    * Resets the current value of the sequence to the one specified as parameter.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          An identifier that specifies the logical name of the database
    *          in which the sequence is defined. The database must be
    *          connected. You can omit this parameter if the sequence name is
    *          unambiguous. If more than one connected database has a sequence
    *          with given name, then you must supply <code>ldbName</code>.
    * @param   newValue
    *          An integer expression assigned as the current value of the
    *          specified sequence. If expression is outside the boundary set
    *          by the initial value (at one end) and the lower limit or upper
    *          limit (at the other end) for the sequence, Progress returns an
    *          error, and the sequence value remains unchanged.
    */
   public static void dynamicSetValue(String seqName, long newValue, character ldbName)
   {
      setValueImpl(ldbName.toJavaType(), seqName, newValue, true, AUTO_TENANT);
   }
   
   /**
    * Maps the <code>DYNAMIC-CURRENT-VALUE(seqName, ldbName) = expr</code>
    * statement from Progress as it is defined in Open Edge 10.x.
    * Resets the current value of the sequence to the one specified as parameter.
    *
    * @param   seqName
    *          A character expression that evaluates to the legacy name of a sequence defined in the Data
    *          Dictionary.
    * @param   ldbName
    *          A character expression that evaluates to the name of a database
    *          in which the sequence is defined. The database must be
    *          connected. You can omit this parameter if the sequence name is
    *          unambiguous. If more than one connected database has a sequence
    *          with given name, then you must supply <code>ldbName</code>.
    * @param   newValue
    *          A numerical expression assigned as the current value of the
    *          specified sequence. If expression is outside the boundary set
    *          by the initial value (at one end) and the lower limit or upper
    *          limit (at the other end) for the sequence, Progress returns an
    *          error, and the sequence value remains unchanged.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    */
   public static void dynamicSetValue(String seqName, NumberType newValue, String ldbName, NumberType tenantId)
   {
      Long tenant = tenantId == null || tenantId.isUnknown() ? null : tenantId.longValue();
      setValueImpl(ldbName, seqName, newValue.isUnknown() ? null : newValue.longValue(), true, tenant);
   }
   
   /**
    * Maps the <code>DYNAMIC-CURRENT-VALUE(seqName, ldbName) = expr</code>
    * statement from Progress as it is defined in Open Edge 10.x.
    * Resets the current value of the sequence to the one specified as parameter.
    *
    * @param   seqName
    *          A character expression that evaluates to the legacy name of a sequence defined in the Data
    *          Dictionary.
    * @param   ldbName
    *          A character expression that evaluates to the name of a database
    *          in which the sequence is defined. The database must be
    *          connected. You can omit this parameter if the sequence name is
    *          unambiguous. If more than one connected database has a sequence
    *          with given name, then you must supply <code>ldbName</code>.
    * @param   newValue
    *          A numerical expression assigned as the current value of the
    *          specified sequence. If expression is outside the boundary set
    *          by the initial value (at one end) and the lower limit or upper
    *          limit (at the other end) for the sequence, Progress returns an
    *          error, and the sequence value remains unchanged.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    */
   public static void dynamicSetValue(String seqName, NumberType newValue, String ldbName, long tenantId)
   {
      setValueImpl(ldbName, seqName, newValue.isUnknown() ? null : newValue.longValue(), true, tenantId);
   }
   
   /**
    * Maps the <code>DYNAMIC-CURRENT-VALUE(seqName, ldbName) = expr</code> 
    * statement from Progress as it is defined in Open Edge 10.x.
    * Resets the current value of the sequence to the one specified as parameter.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          An identifier that specifies the logical name of the database
    *          in which the sequence is defined. The database must be
    *          connected. You can omit this parameter if the sequence name is
    *          unambiguous. If more than one connected database has a sequence
    *          with given name, then you must supply <code>ldbName</code>.
    * @param   newValue
    *          A numerical expression assigned as the current value of the
    *          specified sequence. If expression is outside the boundary set
    *          by the initial value (at one end) and the lower limit or upper
    *          limit (at the other end) for the sequence, Progress returns an
    *          error, and the sequence value remains unchanged.
    */
   public static void dynamicSetValue(String seqName, NumberType newValue, character ldbName)
   {
      setValueImpl(ldbName.toJavaType(),
                   seqName,
                   newValue.isUnknown() ? null : newValue.longValue(),
                   true,
                   AUTO_TENANT);
   }
   
   /**
    * Maps the <code>DYNAMIC-CURRENT-VALUE(seqName, ldbName) = expr</code>
    * statement from Progress as it is defined in Open Edge 10.x.
    * Resets the current value of the sequence to the one specified as parameter.
    *
    * @param   seqName
    *          A character expression that evaluates to the legacy name of a sequence defined in the Data
    *          Dictionary.
    * @param   ldbName
    *          A character expression that evaluates to the name of a database
    *          in which the sequence is defined. The database must be
    *          connected. You can omit this parameter if the sequence name is
    *          unambiguous. If more than one connected database has a sequence
    *          with given name, then you must supply <code>ldbName</code>.
    * @param   newValue
    *          An integer expression assigned as the current value of the
    *          specified sequence. If expression is outside the boundary set
    *          by the initial value (at one end) and the lower limit or upper
    *          limit (at the other end) for the sequence, Progress returns an
    *          error, and the sequence value remains unchanged.
    */
   public static void dynamicSetValue(character seqName, long newValue, String ldbName)
   {
      setValueImpl(ldbName, seqName.toJavaType(), newValue, true, AUTO_TENANT);
   }
   
   /**
    * Maps the <code>DYNAMIC-CURRENT-VALUE(seqName, ldbName) = expr</code> 
    * statement from Progress as it is defined in Open Edge 10.x.
    * Resets the current value of the sequence to the one specified as parameter.
    *
    * @param   seqName
    *          The legacy name of a sequence defined in the Data Dictionary.
    * @param   ldbName
    *          An identifier that specifies the logical name of the database
    *          in which the sequence is defined. The database must be
    *          connected. You can omit this parameter if the sequence name is
    *          unambiguous. If more than one connected database has a sequence
    *          with given name, then you must supply <code>ldbName</code>.
    * @param   newValue
    *          An integer expression assigned as the current value of the
    *          specified sequence. If expression is outside the boundary set
    *          by the initial value (at one end) and the lower limit or upper
    *          limit (at the other end) for the sequence, Progress returns an
    *          error, and the sequence value remains unchanged.
    */
   public static void dynamicSetValue(character seqName, long newValue, character ldbName)
   {
      setValueImpl(ldbName.toJavaType(), seqName.toJavaType(), newValue, true, AUTO_TENANT);
   }
   
   /**
    * Maps the <code>DYNAMIC-CURRENT-VALUE(seqName, ldbName) = expr</code>
    * statement from Progress as it is defined in Open Edge 10.x.
    * Resets the current value of the sequence to the one specified as parameter.
    *
    * @param   seqName
    *          A character expression that evaluates to the legacy name of a sequence defined in the Data
    *          Dictionary.
    * @param   ldbName
    *          A character expression that evaluates to the name of a database
    *          in which the sequence is defined. The database must be
    *          connected. You can omit this parameter if the sequence name is
    *          unambiguous. If more than one connected database has a sequence
    *          with given name, then you must supply <code>ldbName</code>.
    * @param   newValue
    *          A numerical expression assigned as the current value of the
    *          specified sequence. If expression is outside the boundary set
    *          by the initial value (at one end) and the lower limit or upper
    *          limit (at the other end) for the sequence, Progress returns an
    *          error, and the sequence value remains unchanged.
    */
   public static void dynamicSetValue(character seqName, NumberType newValue, String ldbName)
   {
      setValueImpl(ldbName,
                   seqName.toJavaType(),
                   newValue.isUnknown() ? null : newValue.longValue(),
                   true,
                   AUTO_TENANT);
   }
   
   /**
    * Maps the <code>DYNAMIC-CURRENT-VALUE(seqName, ldbName) = expr</code> statement from Progress
    * as it is defined in Open Edge 10.x. 
    * Resets the current value of the sequence to the one specified as parameter.
    * 
    * @param seqName
    *        A character expression that evaluates to the name of a sequence defined in the Data
    *        Dictionary.
    * @param ldbName
    *        A character expression that evaluates to the name of a database in which the sequence
    *        is defined. The database must be connected. You can omit this parameter if the
    *        sequence name is unambiguous. If more than one connected database has a sequence with
    *        given name, then you must supply <code>ldbName</code>.
    * @param newValue
    *        A numerical expression assigned as the current value of the specified sequence. If
    *        expression is outside the boundary set by the initial value (at one end) and the
    *        lower limit or upper limit (at the other end) for the sequence, Progress returns an
    *        error, and the sequence value remains unchanged.
    */
   public static void dynamicSetValue(character seqName, NumberType newValue, character ldbName)
   {
      Long val = newValue.isUnknown() ? null : newValue.longValue();
      setValueImpl(ldbName.toJavaType(), seqName.toJavaType(), val, true, AUTO_TENANT);
   }
   
   /**
    * Maps the <code>DYNAMIC-CURRENT-VALUE(seqName, ldbName) = expr</code> statement from Progress
    * as it is defined in Open Edge 10.x. 
    * Resets the current value of the sequence to the one specified as parameter.
    * 
    * @param seqName
    *        A character expression that evaluates to the name of a sequence defined in the Data
    *        Dictionary.
    * @param ldbName
    *        A character expression that evaluates to the name of a database in which the sequence
    *        is defined. The database must be connected. You can omit this parameter if the
    *        sequence name is unambiguous. If more than one connected database has a sequence with
    *        given name, then you must supply <code>ldbName</code>.
    * @param newValue
    *        A numerical expression assigned as the current value of the specified sequence. If
    *        expression is outside the boundary set by the initial value (at one end) and the
    *        lower limit or upper limit (at the other end) for the sequence, Progress returns an
    *        error, and the sequence value remains unchanged.
    */
   public static void dynamicSetValue(BaseDataType seqName, BaseDataType newValue, BaseDataType ldbName)
   {
      dynamicSetValue(new character(seqName), new int64(newValue), new character(ldbName));
   }
   
   /**
    * Maps the <code>DYNAMIC-CURRENT-VALUE(seqName, ldbName) = expr</code> statement from Progress
    * as it is defined in Open Edge 10.x. 
    * Resets the current value of the sequence to the one specified as parameter.
    * 
    * @param seqName
    *        A character expression that evaluates to the name of a sequence defined in the Data
    *        Dictionary.
    * @param ldbName
    *        A character expression that evaluates to the name of a database in which the sequence
    *        is defined. The database must be connected. You can omit this parameter if the
    *        sequence name is unambiguous. If more than one connected database has a sequence with
    *        given name, then you must supply <code>ldbName</code>.
    * @param newValue
    *        A numerical expression assigned as the current value of the specified sequence. If
    *        expression is outside the boundary set by the initial value (at one end) and the
    *        lower limit or upper limit (at the other end) for the sequence, Progress returns an
    *        error, and the sequence value remains unchanged.
    */
   public static void dynamicSetValue(BaseDataType seqName, BaseDataType newValue, String ldbName)
   {
      dynamicSetValue(new character(seqName), new int64(newValue), new character(ldbName));
   }

   /**
    * Maps the <code>DYNAMIC-CURRENT-VALUE(seqName, ldbName) = expr</code> statement from Progress
    * as it is defined in Open Edge 10.x. 
    * Resets the current value of the sequence to the one specified as parameter.
    * 
    * @param seqName
    *        A character expression that evaluates to the name of a sequence defined in the Data
    *        Dictionary.
    * @param ldbName
    *        A character expression that evaluates to the name of a database in which the sequence
    *        is defined. The database must be connected. You can omit this parameter if the
    *        sequence name is unambiguous. If more than one connected database has a sequence with
    *        given name, then you must supply <code>ldbName</code>.
    * @param newValue
    *        A numerical expression assigned as the current value of the specified sequence. If
    *        expression is outside the boundary set by the initial value (at one end) and the
    *        lower limit or upper limit (at the other end) for the sequence, Progress returns an
    *        error, and the sequence value remains unchanged.
    */
   public static void dynamicSetValue(String seqName, BaseDataType newValue, BaseDataType ldbName)
   {
      dynamicSetValue(new character(seqName), new int64(newValue), new character(ldbName));
   }

   /**
    * Maps the <code>DYNAMIC-CURRENT-VALUE(seqName, ldbName) = expr</code> statement from Progress
    * as it is defined in Open Edge 10.x. 
    * Resets the current value of the sequence to the one specified as parameter.
    * 
    * @param seqName
    *        A character expression that evaluates to the name of a sequence defined in the Data
    *        Dictionary.
    * @param ldbName
    *        A character expression that evaluates to the name of a database in which the sequence
    *        is defined. The database must be connected. You can omit this parameter if the
    *        sequence name is unambiguous. If more than one connected database has a sequence with
    *        given name, then you must supply <code>ldbName</code>.
    * @param newValue
    *        A numerical expression assigned as the current value of the specified sequence. If
    *        expression is outside the boundary set by the initial value (at one end) and the
    *        lower limit or upper limit (at the other end) for the sequence, Progress returns an
    *        error, and the sequence value remains unchanged.
    */
   public static void dynamicSetValue(BaseDataType seqName, long newValue, BaseDataType ldbName)
   {
      dynamicSetValue(new character(seqName), new int64(newValue), new character(ldbName));
   }
   
   /**
    * Maps the <code>DYNAMIC-CURRENT-VALUE(seqName, ldbName) = expr</code> statement from Progress
    * as it is defined in Open Edge 10.x. 
    * Resets the current value of the sequence to the one specified as parameter.
    * 
    * @param seqName
    *        A character expression that evaluates to the name of a sequence defined in the Data
    *        Dictionary.
    * @param ldbName
    *        A character expression that evaluates to the name of a database in which the sequence
    *        is defined. The database must be connected. You can omit this parameter if the
    *        sequence name is unambiguous. If more than one connected database has a sequence with
    *        given name, then you must supply <code>ldbName</code>.
    * @param newValue
    *        A numerical expression assigned as the current value of the specified sequence. If
    *        expression is outside the boundary set by the initial value (at one end) and the
    *        lower limit or upper limit (at the other end) for the sequence, Progress returns an
    *        error, and the sequence value remains unchanged.
    */
   public static void dynamicSetValue(BaseDataType seqName, long newValue, String ldbName)
   {
      dynamicSetValue(new character(seqName), new int64(newValue), new character(ldbName));
   }

   /**
    * Maps the <code>DYNAMIC-CURRENT-VALUE(seqName, ldbName) = expr</code> statement from Progress
    * as it is defined in Open Edge 10.x. 
    * Resets the current value of the sequence to the one specified as parameter.
    * 
    * @param seqName
    *        A character expression that evaluates to the name of a sequence defined in the Data
    *        Dictionary.
    * @param ldbName
    *        A character expression that evaluates to the name of a database in which the sequence
    *        is defined. The database must be connected. You can omit this parameter if the
    *        sequence name is unambiguous. If more than one connected database has a sequence with
    *        given name, then you must supply <code>ldbName</code>.
    * @param newValue
    *        A numerical expression assigned as the current value of the specified sequence. If
    *        expression is outside the boundary set by the initial value (at one end) and the
    *        lower limit or upper limit (at the other end) for the sequence, Progress returns an
    *        error, and the sequence value remains unchanged.
    */
   public static void dynamicSetValue(String seqName, long newValue, BaseDataType ldbName)
   {
      dynamicSetValue(new character(seqName), new int64(newValue), new character(ldbName));
   }

   /**
    * Lookups the internal data structure representing a sequence object.
    *
    * @param   dbName
    *          The logical name or alias of the database.
    * @param   name
    *          The sql name of the sequence.
    *
    * @return  The named {@code Sequence} from the database and {@code null} if something is wrong
    *          (database not connected, sequence does not exist).
    */
   public static Sequence getSequence(String dbName, String name)
   {
      Database database = ConnectionManager.get().getDatabase(dbName);
      if (database == null)
      {
         return null; // database not connected ? 
      }
      
      String schema = DatabaseManager.getSchema(database);
      if (schema == null)
      {
         return null;   // unknown schema?
      }
      
      HashMap<String, Sequence> dbSeqList = sequences.get(schema);
      if (dbSeqList == null)
      {
         return null;   // schema not registered ?
      }
      
      return dbSeqList.get(name.toLowerCase());
   }
   
   /**
    * Prepare the sequences from a specified database for usage. The set of sequences is obtained from
    * {@code _Sequence enum} form from the database's location. It is possible that the enum is not created
    * at all when there are no sequences defined in the database.
    * 
    * @param   database
    *          The database to be analyzed.
    * @param   schema
    *          The database's schema.
    */
   public static void prepare(Database database, String schema)
   {
      if (!database.isPrimary())
      {
         return; // no sequences for this database
      }
      
      Class<?> seqEnumClass;
      String sequenceEnumName = 
            DmoMetadataManager.getDmoBasePackage() + "." + database.getName() + "._Sequences";
      try
      {
         seqEnumClass = Class.forName(sequenceEnumName);
      }
      catch (ClassNotFoundException e)
      {
         // the _Sequences class could not be loaded. There are no sequences defined for this database.
         return;
      }
      
      for (Field field : seqEnumClass.getDeclaredFields())
      {
         com.goldencode.p2j.persist.annotation.Sequence seqAnn =
               field.getAnnotation(com.goldencode.p2j.persist.annotation.Sequence.class);
         if (seqAnn == null)
         {
            // the enums have some hidden fields
            continue;
         }
         
         addSequenceDefinition(schema,
                               seqAnn.legacy(),
                               seqAnn.name(),
                               seqAnn.start(),
                               seqAnn.increment(),
                               seqAnn.minValue(),
                               seqAnn.maxValue(),
                               seqAnn.cycle(),
                               seqAnn.multiTenant());
      }
   }
   
   /**
    * Implementation of all cases of querying the sequence values.
    *
    * @param   next
    *          If {@code NEXT}, the next value of the sequence is returned.
    *          If {@code CURRENT} the current value is returned.
    * @param   ldbName
    *          The legacy database name. In static mode, the {@code null} / {@code ?} (unknown) value will
    *          attempt to detect the database dynamically. If operation fails, unknown value is returned.
    *          In dynamic mode, this is an error and an appropriate error condition will be raised. 
    * @param   seqLegacyName
    *          The sequence legacy name. 
    * @param   dynamic
    *          Activates the dynamic sequence name resolution mode.
    * @param   tenantId
    *          The tenant id. If present (not null) it is checked. If not it is computed as
    *          {@code tenant-id(ldbName}).
    *
    * @return  The (new) value of the sequence, as requested.
    */
   private static int64 getValueImpl(boolean next,
                                     String ldbName,
                                     String seqLegacyName,
                                     boolean dynamic,
                                     Long tenantId)
   {
      if (ldbName == null || ldbName.trim().isEmpty())
      {
         if (dynamic)
         {
            ErrorManager.recordOrThrowError(12747);
            // You must provide a valid connected database name to dynamic sequence functions. (12747)
            return new int64();
         }
         
         ldbName = getDatabaseForSequence(seqLegacyName);
         if (ldbName == null)
         {
            // database could not be identified
            return new int64();
         }
      }
      else
      {
         // if an alias was used, switch to logical name
         ldbName = ConnectionManager.get().getLDBName(ldbName);
      }
      
      String sqlSeqName = resolveDynamicName(seqLegacyName, ldbName);
      if (sqlSeqName == null)
      {
         if (dynamic)
         {
            ErrorManager.recordOrThrowError(12748);
            // Unable to evaluate sequence name for dynamic sequence function. (12748)
            return new int64();
         }
         
         // is this possible? This is a compile-time error. The sequence must exist!
         ErrorManager.throwError(3588, seqLegacyName, "");
         // Sequence <sequence> not found. (3588)
         
         return new int64();
      }
      
      SequenceHandler handler = getSequenceHandler(ldbName);
      return next ? handler.getNextValue(sqlSeqName, tenantId)
                  : handler.getCurrentValue(sqlSeqName, tenantId);
   }
   
   /**
    * Implementation of all cases of manual update of a sequence's value.
    *
    * @param   ldbName
    *          The legacy database name. In static mode, the {@code null} / {@code ?} (unknown) value will
    *          attempt to detect the database dynamically. If operation fails, unknown value is returned.
    *          In dynamic mode, this is an error and an appropriate error condition will be raised. 
    * @param   seqLegacyName
    *          The sequence legacy name.
    * @param   val
    *          The new value to be set.
    * @param   dynamic
    *          Activates the dynamic sequence name resolution mode.
    * @param   tenantId
    *          The optional tenant-id. Especially used with super-tenants. Can be specified with default (but
    *          must be 0) or regular tenants (but must be {@code tenant-id(ldbName)}). If this is invalid a
    *          specific error condition is raised.
    */
   private static void setValueImpl(String ldbName,
                                    String seqLegacyName,
                                    Long val,
                                    boolean dynamic,
                                    Long tenantId)
   {
      if (val == null)
      {
         ExternalProgramWrapper epw = (ExternalProgramWrapper) ProcedureManager.thisProcedure().getResource();
         ErrorManager.recordOrThrowError(143, epw.getFileName().toJavaType(), "");
         // ** <program-name>: Unable to evaluate field for assignment. (143)
         return;
      }
      
      if (ldbName == null || ldbName.trim().isEmpty())
      {
         if (dynamic)
         {
            ErrorManager.recordOrThrowError(12747);
            // You must provide a valid connected database name to dynamic sequence functions. (12747)
            return;
         }
         
         ldbName = getDatabaseForSequence(seqLegacyName);
         if (ldbName == null)
         {
            ErrorManager.recordOrThrowError(3133, seqLegacyName.toUpperCase(), "");
            // SYSTEM ERROR: Sequence <sequence name> not found. (3133)
            return;
         }
      }
      else
      {
         // if an alias was used, switch to logical name
         ldbName = ConnectionManager.get().getLDBName(ldbName);
      }

      
      String sqlSeqName = resolveDynamicName(seqLegacyName, ldbName);
      if (sqlSeqName == null)
      {
         if (dynamic)
         {
            ErrorManager.recordOrThrowError(12748);
            // Unable to evaluate sequence name for dynamic sequence function. (12748)
            return;
         }
         
         // is this possible? 
         return;
      }
      
      getSequenceHandler(ldbName).setValue(sqlSeqName, val, tenantId);
   }
   
   /**
    * Seeks the database in which the sequence is defined. It is assumed that there should no conflicts or the
    * first found database is returned. This method is called when some (static) sequence function has been
    * called without the last parameter (ldbName).
    * As a side effect, if the database is found, it is guaranteed that the appropriate
    * {@code SequenceHandler} has been loaded.
    *
    * @param   legacyName
    *          The legacy sequence name of the sequence to lookup after.
    *
    * @return The name of the database where the sequence is defined.
    */
   private static String getDatabaseForSequence(String legacyName)
   {
      int connectedDbCount = ConnectionManager.getConnectedDbCount();
      for (int i = 0; i < connectedDbCount; i++)
      {
         String ldbName = ConnectionManager.ldbName(i + 1).toJavaType();
         SequenceHandler handler = getSequenceHandler(ldbName);
         
         String sqlSeqName = resolveDynamicName(legacyName, ldbName);
         if (handler != null && handler.contains(sqlSeqName))
         {
            return ldbName;
         }
      }
      
      return null;
   }
   
   /**
    * Resolve the legacy name to actual sql name of a sequence. 
    * 
    * @param   legacyName
    *          The name of the sequence in 4GL.
    * @param   schema
    *          The schema of the sequence. 
    *
    * @return  The sql-legal name of the schema.
    */
   private static String resolveDynamicName(String legacyName, String schema)
   {
      HashMap<String, String> legSeqMap = legacyMap.get(schema.toLowerCase());
      if (legSeqMap == null)
      {
         // TODO: sql name is the same as legacy name, but lowercased - this is incorrect for case-sensitive
         //       dialects like MariaDB
         return legacyName.toLowerCase();
      }
      else
      {
         String sqlName = legSeqMap.get(legacyName.toLowerCase());
         // TODO: if null, sql name is the same as legacy name, but lowercased - this is incorrect for 
         //       case-sensitive dialects like MariaDB
         return sqlName != null ? sqlName : legacyName.toLowerCase();
      }
   }
   
   /**
    * Factory method for obtaining a sequence object for a database.  If some
    * settings is not found in directory a default <code>SequenceHandler</code> is
    * returned by default.
    *
    * @param   ldbName
    *          The name of the database
    *
    * @return  An instance of Sequence that will to which the internal
    *          functionality will be delegated.
    */
   private static SequenceHandler getSequenceHandler(String ldbName)
   {
      synchronized (SequenceManager.class)
      {
         if (seqHandlers.containsKey(ldbName))
         {
            // sequence handler already prepared for this database
            return seqHandlers.get(ldbName);
         }
         
         // as the database name can be dynamically passed, check if the name is valid 
         if (ConnectionManager.get().getDatabase(ldbName) == null)
         {
            ErrorManager.recordOrThrowError(3141,
                  "Database " + ldbName + " does not exist or is not open");
            return defaultHandler;
         }
         
         // Obtain the appropriate sequence handler using the Dialect of the database
         Persistence persistence = ConnectionManager.getPersistence(ldbName);
         Dialect dialect = persistence.getDialect();
         SequenceHandler sequenceHandler = dialect.createSequenceHandler(ldbName);
         if (sequenceHandler == null) 
         {
            // This should not happen, but to be on the safe side, use the default handler:
            sequenceHandler = defaultHandler;
            
            CentralLogger LOG = CentralLogger.get(SequenceHandler.class);
            LOG.logp(Level.WARNING,
                     SequenceManager.class.getName(),
                     "getSequenceHandler()",
                     "Could not detect dialect for " + ldbName);
         }
         
         // save to internal cache for further fast access
         seqHandlers.put(ldbName, sequenceHandler);
         return sequenceHandler;
      }
   }
   
   /**
    * Creates the internal data structure representing a sequence object and add it to in-memory list. <p>
    * This method is only called at startup time or when the database is initializing.
    * 
    * @param   schema
    *          The schema/database.
    * @param   legName
    *          The legacy name of the sequence (as it was defined in 4GL).
    * @param   sqlName
    *          The sql-legal name of the sequence.
    * @param   sesInit
    *          The initial value of the sequence.
    * @param   seqInc
    *          The increment value of the sequence.
    * @param   seqMin
    *          The minimum value of the sequence.
    * @param   seqMax
    *          The maximum value of the sequence.
    * @param   seqCycle
    *          The cycle flag of the sequence.
    * @param   mt
    *          Multi-tenant flag.
    */
   private static void addSequenceDefinition(String  schema,
                                             String  legName,
                                             String  sqlName,
                                             long    sesInit,
                                             long    seqInc,
                                             long    seqMin,
                                             long    seqMax,
                                             boolean seqCycle,
                                             boolean mt)
   {
      // first check if Sequence already exists
      Sequence sequence = getSequence(schema, sqlName);
      if (sequence != null)
      {
         return;
      }
      
      // sequence does not exist, create it now
      sequence = new Sequence(schema, legName, sqlName, sesInit, seqMin, seqMax, seqInc, seqCycle, mt);
      
      // normalize schema lookup key
      String schemaKey = schema.toLowerCase();
      
      // if missing, create it now
      HashMap<String, Sequence> dbSeqMap = sequences.computeIfAbsent(schemaKey, k -> new HashMap<>());
      
      // add the object to database list
      dbSeqMap.put(sqlName.toLowerCase(), sequence);
      
      // add it to legacy map only when sqlName != seqName
      // CA: always register the sequence names
      // if (!sqlName.equals(seqName))
      {
         // if missing, create it now
         HashMap<String, String> legSeqMap = legacyMap.computeIfAbsent(schemaKey, k -> new HashMap<>());
         
         // add the object to database list
         legSeqMap.put(legName.toLowerCase(), sqlName);
      }
   }
}