# StaticTempTable.java

    /*
    ** Module   : StaticTempTable.java
    ** Abstract : Static 4GL temp-table object.
    **
    ** Copyright (c) 2013-2025, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- ---------------------------------------Description---------------------------------------
    ** 001 SVL 20131115 Created initial version. Most of TODOs is just about throwing a proper error.
    ** 002 CA  20131209 Fixed implicit deletion of static temp-tables (the static resource gets
    **                  deleted ONLY when its INSTANTIATING-PROCEDURE gets deleted).
    ** 003 HC  20131215 Implemented ADM-DATA and UNIQUE-ID attribute.
    ** 004 SVL 20140106 Some functions were implemented.
    ** 005 SVL 20140124 Implemented some functions that return error for static tables.
    ** 006 SVL 20140205 Moved COPY-TEMP-TABLE to the parent class.
    ** 007 ECF 20150324 Removed cleanup of TableMapper mapping from resourceDelete.
    ** 008 OM  20151026 Implemented UNDO attribute setter to super class.
    ** 009 CA  20151211 Static temp-table which are shared globally can't be deleted (implicitly or
    **                  explicitly), they survive for the life of the context.
    **                  Also, when a temp-table is deleted, all its associated buffers must be deleted.
    ** 010 EVL 20160223 Javadoc fixes to make compatible with Oracle Java 8 for Solaris 10.
    ** 011 ECF 20160225 Added getDMOInterface method.
    ** 012 OM  20181114 Added NamedSerializable interface implementation.
    ** 013 OM  20190405 Renamed createTableLike() to createLike.
    ** 014 SVL 20190614 Support for COLUMN-CODEPAGE.
    ** 015 OM  20190514 Added P11.7 syntax support for TEMP-TABLE-PREPARE.
    ** 016 SVL 20190801 Added get/setCodePageSupplier.
    ** 017 ECF 20200906 New ORM implementation.
    ** 018 AIL 20200914 Implemented _prepared abstract method.
    **     AIL 20200915 Moved prepared method to superclass.
    **     OM  20201002 Use DmoMeta cached information instead of map lookups.
    **     OM  20201120 Extracted SERIALIZE-NAME to dedicated interface. Implemented CLEAR state awareness.
    **     OM  20210106 Fixed 2nd parameter of TEMP-TABLE-PREPARE.
    **     OM  20210127 Replaced TableMapper.getLegacyName() triple map lookup with direct access to local
    **                  dmoMeta.legacyTable.
    **     OM  20210404 Small javadoc updates.
    **     ECF 20210506 Use RecordBuffer.getDmoInfo() getter instead of direct field access to prevent
    **                  NPE in proxy case.
    **     CA  20210626 Do not delete the master shared temp-table until the last of its associated buffers (i.e.
    **                  child shared temp-tables) is deleted.
    **     OM  20210921 Initialized serializeName, xmlNodeName, namespaceUri, and namespacePrefix from DmoInfo.
    **     CA  20221006 The equals and hashCode methods must not be implemented by resources.
    **     CA  20220618 toString() dumps the entire table content as JSON.
    **     HC  20230116 Replaced some handle usages with the actual wrapped resources for
    **                  performance.
    **     CA  20230116 Avoid using handle.unwrap, handle.getReference or other BDT usage from within FWD runtime.
    ** 019 IAS 20230529 Added 'readTable' method.
    ** 020 AI  20240314 Overloaded addFieldLike with String, character.
    ** 021 EAB 20240423 Rewrote toString method in order to imitate the result returned by writeJson().
    ** 022 AI  20240531 Overloaded addFieldLike with character, String.
    ** 023 AP  20250129 Refactored toString method to use the RecordBufferSerializer and do the actual JSON
    **                  serialization using jackson library.
    ** 024 ICP 20250129 Used logical constants to leverage cached values.
    ** 025 ES  20250327 Initialize to defaultBuffer before setting up its attributes.
    */

    /*
    ** 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 com.fasterxml.jackson.core.*;
    import com.fasterxml.jackson.databind.*;
    import com.goldencode.p2j.persist.orm.*;
    import com.goldencode.p2j.persist.serial.*;
    import com.goldencode.p2j.util.*;
    import com.goldencode.p2j.util.logging.*;
    import java.sql.SQLException;
    import java.util.*;
    import java.util.function.*;

    /**
     * Static 4GL temp-table object.
     *
     * TODO: defaultBuffer() is called multiple times in various methods. Should we cache it?
     */
    public class StaticTempTable
    extends AbstractTempTable
    {
       /** Logger */
       private static final CentralLogger LOG = CentralLogger.get(StaticTempTable.class);

       /**
        * Code pages of CLOB fields keyed by ORM property names.
        */
       private Map<String, String> codePages;

       /**
        * Code page suppliers of CLOB fields keyed by ORM property names.
        */
       private Map<String, Supplier> codePagesSuppliers;

       /**
        * Flag indicating if the delete must be forced (for master temp-tables which had their instantiating
        * program deleted and they must survive until the last child share gets deleted).
        */
       private boolean forceDelete = false;

       /**
        * Default constructor.
        *
        * @param defaultBuffer
        *        Default buffer of the target table.
        */
       public StaticTempTable(Temporary defaultBuffer)
       {
          super(false);

          TemporaryBuffer buffer = (TemporaryBuffer) ((BufferImpl) defaultBuffer).buffer();
          DmoMeta dmoInfo = buffer.getDmoInfo();

          this.defaultBuffer = (BufferImpl) defaultBuffer;

          if (!dmoInfo.serializeName.isEmpty())
          {
             super.setSerializeName(dmoInfo.serializeName);
          }
          if (!dmoInfo.xmlNodeName.isEmpty())
          {
             super.setXmlNodeName(dmoInfo.xmlNodeName);
          }
          if (!dmoInfo.namespaceUri.isEmpty())
          {
             super.namespaceURI(dmoInfo.namespaceUri);
          }
          if (!dmoInfo.namespacePrefix.isEmpty())
          {
             super.namespacePrefix(dmoInfo.namespacePrefix);
          }

          TableMapper.mapTemporaryTable(this);
          this.name = dmoInfo.legacyTable;
          super.undoable = buffer.isUndoable();
       }

       /**
        * Obtain the {@code DmoMeta} structure which contains the legacy meta information.
        *
        * @return  {@code DmoMeta} structure which contains the legacy meta information
        */
       @Override
       public DmoMeta getDmoMeta()
       {
          return defaultBuffer().getDmoInfo();
       }

       /**
        * Get DMO interface associated with this table.
        *
        * @return DMO interface associated with this table or <code>null</code> if the
        *         table is not initialized yet.
        */
       @Override
       public Class<? extends DataModelObject> getDMOInterface()
       {
          if (!valid())
          {
             throw new IllegalStateException("Cannot get DMO class for the static temp table, " +
                                             "the table scope is already closed");
          }

          return defaultBuffer().getDMOInterface();
       }

       /**
        * Get the combined DMO and Buffer grouping interface associated with this table.
        *
        * @return  DMO and Buffer grouping interface.
        */
       @Override
       public Class<? extends TempTableBuffer> getDMOBufInterface()
       {
          if (!valid())
          {
             throw new IllegalStateException("Cannot get DMO class for the static temp table, " +
                                             "the table scope is already closed");
          }

          return (Class<? extends TempTableBuffer>) defaultBuffer().getDMOBufInterface();
       }

       /**
        * Get DMO implementation class associated with this table.
        *
        * @return DMO implementation class associated with this table or <code>null</code> if the
        *         table is not initialized yet.
        */
       @Override
       public Class<? extends Record> getDMOClass()
       {
          if (!valid())
          {
             throw new IllegalStateException("Cannot get DMO class for the static temp table, " +
                                             "the table scope is already closed");
          }

          return defaultBuffer().getDMOImplementationClass();
       }

       /**
        * Duplicates the structure of an existing table, copying the field
        * definitions, and optionally, the indexes.
        * This method is the P2J equivalent of <code>CREATE-LIKE</code> method
        * of Progress 4GL.
        *
        * @param   hbuf
        *          A handle to a buffer or table from which to copy the definitions.
        *
        * @return  <code>true</code> on success.
        */
       @Override
       public logical createLike(handle hbuf)
       {
          displayCreateLikeNotFirst();
          return new logical();
       }

       /**
        * Duplicates the structure of an existing table, copying the field
        * definitions, and optionally, the indexes.
        * This method is the P2J equivalent of <code>CREATE-LIKE</code> method
        * of Progress 4GL.
        *
        * @param   tableName
        *          The name of a table to create the copy of.
        *
        * @return  <code>true</code> on success.
        */
       @Override
       public logical createLike(String tableName)
       {
          displayCreateLikeNotFirst();
          return new logical();
       }

       /**
        * Duplicates the structure of an existing table, copying the field
        * definitions, and optionally, the indexes.
        * This method is the P2J equivalent of <code>CREATE-LIKE</code> method
        * of Progress 4GL.
        *
        * @param   tableName
        *          The name of a table to create the copy of.
        *
        * @return  <code>true</code> on success.
        */
       @Override
       public logical createLike(character tableName)
       {
          displayCreateLikeNotFirst();
          return new logical();
       }

       /**
        * Duplicates the structure of an existing table, copying the field
        * definitions, and optionally, the indexes.
        * This method is the P2J equivalent of <code>CREATE-LIKE</code> method
        * of Progress 4GL.
        *
        * @param   hbuf
        *          A handle to a buffer or table from which to copy the definitions.
        * @param   indexName
        *          The name of a single index which is copied from the source table.
        *
        * @return  <code>true</code> on success.
        */
       @Override
       public logical createLike(handle hbuf, String indexName)
       {
          displayCreateLikeNotFirst();
          return new logical();
       }

       /**
        * Duplicates the structure of an existing table, copying the field
        * definitions, and optionally, the indexes.
        * This method is the P2J equivalent of <code>CREATE-LIKE</code> method
        * of Progress 4GL.
        *
        * @param   hbuf
        *          A handle to a buffer or table from which to copy the definitions.
        * @param   indexName
        *          The name of a single index which is copied from the source table.
        *
        * @return  <code>true</code> on success.
        */
       @Override
       public logical createLike(handle hbuf, character indexName)
       {
          displayCreateLikeNotFirst();
          return new logical();
       }

       /**
        * Duplicates the structure of an existing table, copying the field
        * definitions, and optionally, the indexes.
        * This method is the P2J equivalent of <code>CREATE-LIKE</code> method
        * of Progress 4GL.
        *
        * @param   tableName
        *          The name of a table to create the copy of.
        * @param   indexName
        *          The name of a single index which is copied from the source table.
        *
        * @return  <code>true</code> on success.
        */
       @Override
       public logical createLike(String tableName, String indexName)
       {
          displayCreateLikeNotFirst();
          return new logical();
       }

       /**
        * Duplicates the structure of an existing table, copying the field
        * definitions, and optionally, the indexes.
        * This method is the P2J equivalent of <code>CREATE-LIKE</code> method
        * of Progress 4GL.
        *
        * @param   tableName
        *          The name of a table to create the copy of.
        * @param   indexName
        *          The name of a single index which is copied from the source table.
        *
        * @return  <code>true</code> on success.
        */
       @Override
       public logical createLike(character tableName, character indexName)
       {
          displayCreateLikeNotFirst();
          return new logical();
       }

       /**
        * Adds a field with the specified properties to the temp-table.
        * This method is the P2J equivalent of <code>ADD-NEW-FIELD</code> method
        * of Progress 4GL.
        *
        * @param   name
        *          The name of the field to be created in the temp-table.
        * @param   type
        *          The data type of the specified field.
        *
        * @return  <code>true</code> on success.
        */
       public logical addNewField(character name, character type)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds a field with the specified properties to the temp-table.
        * This method is the P2J equivalent of <code>ADD-NEW-FIELD</code> method
        * of Progress 4GL.
        *
        * @param   name
        *          The name of the field to be created in the temp-table.
        * @param   type
        *          The data type of the specified field.
        * @param   extent
        *          An integer expression specifying the extent of an array.
        *
        * @return  <code>true</code> on success.
        */
       public logical addNewField(character name, character type, integer extent)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds a field with the specified properties to the temp-table.
        * This method is the P2J equivalent of <code>ADD-NEW-FIELD</code> method
        * of Progress 4GL.
        *
        * @param   name
        *          The name of the field to be created in the temp-table.
        * @param   type
        *          The data type of the specified field.
        * @param   extent
        *          An integer expression specifying the extent of an array.
        * @param   format
        *          The data format for the defined data type. If null or unknown,
        *          the default format will be used.
        *
        * @return  <code>true</code> on success.
        */
       public logical addNewField(character name, character type, integer extent, character format)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds a field with the specified properties to the temp-table.
        * This method is the P2J equivalent of <code>ADD-NEW-FIELD</code> method
        * of Progress 4GL.
        *
        * @param   name
        *          The name of the field to be created in the temp-table.
        * @param   type
        *          The data type of the specified field.
        * @param   extent
        *          An integer expression specifying the extent of an array.
        * @param   format
        *          The data format for the defined data type. If null or unknown,
        *          the default format will be used.
        * @param   initial
        *          An expression that evaluates to the initial value of the
        *          defined field.
        *          TODO: this method will probably be overloaded because of this.
        *
        * @return  <code>true</code> on success.
        */
       public logical addNewField(character name,
                                  character type,
                                  integer extent,
                                  character format,
                                  BaseDataType initial)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds a field with the specified properties to the temp-table.
        * This method is the P2J equivalent of <code>ADD-NEW-FIELD</code> method
        * of Progress 4GL.
        *
        * @param   name
        *          The name of the field to be created in the temp-table.
        * @param   type
        *          The data type of the specified field.
        * @param   extent
        *          An integer expression specifying the extent of an array.
        * @param   format
        *          The data format for the defined data type. If null or unknown,
        *          the default format will be used.
        * @param   initial
        *          An expression that evaluates to the initial value of the
        *          defined field.
        *          TODO: this method will probably be overloaded because of this.
        * @param   label
        *          The label of the defined field. If null or unknown the name
        *          parameter will be used.
        *
        * @return  <code>true</code> on success.
        */
       public logical addNewField(character name,
                                  character type,
                                  integer extent,
                                  character format,
                                  BaseDataType initial,
                                  character label)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds a field with the specified properties to the temp-table.
        * This method is the P2J equivalent of <code>ADD-NEW-FIELD</code> method
        * of Progress 4GL.
        *
        * @param   name
        *          The name of the field to be created in the temp-table.
        * @param   type
        *          The data type of the specified field.
        * @param   extent
        *          An integer expression specifying the extent of an array.
        * @param   format
        *          The data format for the defined data type. If null or unknown,
        *          the default format will be used.
        * @param   initial
        *          An expression that evaluates to the initial value of the
        *          defined field.
        *          TODO: this method will probably be overloaded because of this.
        * @param   label
        *          The label of the defined field. If null or unknown the name
        *          parameter will be used.
        * @param   columnLabel
        *          The label of the column associated with the defined field
        *
        * @return  <code>true</code> on success.
        */
       public logical addNewField(character name,
                                  character type,
                                  integer extent,
                                  character format,
                                  BaseDataType initial,
                                  character label,
                                  character columnLabel)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds a new empty index with the specified name to the temp-table. Index
        * components must be added with the <code>ADD-INDEX-FIELD()</code> method.
        * This method is the P2J equivalent of <code>ADD-NEW-INDEX</code> method
        * of Progress 4GL.
        *
        * @param   name
        *          The name of the index to be created.
        *
        * @return  <code>true</code> on success.
        */
       public logical addNewIndex(character name)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds a new empty index with the specified name to the temp-table. Index
        * components must be added with the <code>ADD-INDEX-FIELD()</code> method.
        * This method is the P2J equivalent of <code>ADD-NEW-INDEX</code> method
        * of Progress 4GL.
        *
        * @param   name
        *          The name of the index to be created.
        * @param   unique
        *          TRUE if this index is unique.
        *
        * @return  <code>true</code> on success.
        */
       public logical addNewIndex(character name, logical unique)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds a new empty index with the specified name to the temp-table. Index
        * components must be added with the <code>ADD-INDEX-FIELD()</code> method.
        * This method is the P2J equivalent of <code>ADD-NEW-INDEX</code> method
        * of Progress 4GL.
        *
        * @param   name
        *          The name of the index to be created.
        * @param   unique
        *          TRUE if this index is unique.
        * @param   primary
        *          TRUE if this is the primary index.
        *
        * @return  <code>true</code> on success.
        */
       public logical addNewIndex(character name, logical unique, logical primary)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds a new empty index with the specified name to the temp-table. Index
        * components must be added with the <code>ADD-INDEX-FIELD()</code> method.
        * This method is the P2J equivalent of <code>ADD-NEW-INDEX</code> method
        * of Progress 4GL.
        *
        * @param   name
        *          The name of the index to be created.
        * @param   unique
        *          TRUE if this index is unique.
        * @param   primary
        *          TRUE if this is the primary index.
        * @param   word
        *          TRUE if this is a word index.
        *
        * @return  <code>true</code> on success.
        */
       public logical addNewIndex(character name, logical unique, logical primary, logical word)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds to the temp-table a field like the one specified.
        * This method is the P2J equivalent of <code>ADD-LIKE-FIELD</code> method of Progress 4GL.
        *
        * @param   name
        *          The name of the field to be created in the temp-table.
        * @param   source
        *          Database field name from which to copy the field. The table
        *          name must be qualified with the database name.
        *
        * @return  <code>true</code> on success.
        */
       public logical addFieldLike(String name, String source)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds to the temp-table a field like the one specified.
        * This method is the P2J equivalent of <code>ADD-LIKE-FIELD</code> method of Progress 4GL.
        *
        * @param   name
        *          The name of the field to be created in the temp-table.
        * @param   source
        *          Database field name from which to copy the field. The table
        *          name must be qualified with the database name.
        *
        * @return  <code>true</code> on success.
        */
       public logical addFieldLike(String name, character source)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds to the temp-table a field like the one specified.
        * This method is the P2J equivalent of <code>ADD-LIKE-FIELD</code> method of Progress 4GL.
        *
        * @param   name
        *          The name of the field to be created in the temp-table.
        * @param   source
        *          Database field name from which to copy the field. The table
        *          name must be qualified with the database name.
        *
        * @return  <code>true</code> on success.
        */
       public logical addFieldLike(character name, String source)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds to the temp-table a field like the one specified.
        * This method is the P2J equivalent of <code>ADD-LIKE-FIELD</code> method of Progress 4GL.
        *
        * @param   name
        *          The name of the field to be created in the temp-table.
        * @param   source
        *          Database field name from which to copy the field. The table
        *          name must be qualified with the database name.
        *
        * @return  <code>true</code> on success.
        */
       public logical addFieldLike(character name, character source)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds to the temp-table a field like the one specified.
        * This method is the P2J equivalent of <code>ADD-LIKE-FIELD</code> method of Progress 4GL.
        *
        * @param   name
        *          The name of the field to be created in the temp-table.
        * @param   source
        *          Handle to field name from which to copy the field.
        *
        * @return  <code>true</code> on success.
        */
       public logical addFieldLike(String name, handle source)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds to the temp-table a field like the one specified.
        * This method is the P2J equivalent of <code>ADD-LIKE-FIELD</code> method of Progress 4GL.
        *
        * @param   name
        *          The name of the field to be created in the temp-table.
        * @param   source
        *          Handle to field name from which to copy the field.
        *
        * @return  <code>true</code> on success.
        */
       public logical addFieldLike(character name, handle source)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds to the temp-table an index like the one specified.
        * This method is the P2J equivalent of <code>ADD-LIKE-INDEX</code> method of Progress 4GL.
        *
        * @param   name
        *          The name of the index to which the source index is being copied. Progress ignores
        *          this option and uses the name of the source index instead.
        * @param   sourceName
        *          The name of the index in the source table that is being copied
        *          to the temp-table.
        * @param   dbTable
        *          The database table name from which to copy the index.
        *
        * @return  <code>true</code> on success.
        */
       public logical addIndexLike(String name, String sourceName, String dbTable)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds to the temp-table an index like the one specified.
        * This method is the P2J equivalent of <code>ADD-LIKE-INDEX</code> method
        * of Progress 4GL.
        *
        * @param   name
        *          The name of the index to which the source index is being copied. Progress ignores
        *          this option and uses the name of the source index instead.
        * @param   sourceName
        *          The name of the index in the source table that is being copied
        *          to the temp-table.
        * @param   dbTable
        *          The database table name from which to copy the index.
        *
        * @return  <code>true</code> on success.
        */
       public logical addIndexLike(character name, character sourceName, character dbTable)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds to the temp-table an index like the one specified.
        * This method is the P2J equivalent of <code>ADD-LIKE-INDEX</code> method
        * of Progress 4GL.
        *
        * @param   name
        *          The name of the index to which the source index is being copied. Progress ignores
        *          this option and uses the name of the source index instead.
        * @param   sourceName
        *          The name of the index in the source table that is being copied
        *          to the temp-table.
        * @param   sourceBuffer
        *          Buffer handle from which to copy the index.
        *
        * @return  <code>true</code> on success.
        */
       public logical addIndexLike(String name, String sourceName, handle sourceBuffer)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds to the temp-table an index like the one specified.
        * This method is the P2J equivalent of <code>ADD-LIKE-INDEX</code> method
        * of Progress 4GL.
        *
        * @param   name
        *          The name of the index to which the source index is being copied. Progress ignores
        *          this option and uses the name of the source index instead.
        * @param   sourceName
        *          The name of the index in the source table that is being copied
        *          to the temp-table.
        * @param   sourceBuffer
        *          Buffer handle from which to copy the index.
        *
        * @return  <code>true</code> on success.
        */
       public logical addIndexLike(character name, character sourceName, handle sourceBuffer)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Signals that all the field and index definitions for a temp-table
        * have been provided. After the call to this method no fields and indexes
        * can be added to this temporary table.
        * This method is the P2J equivalent of <code>TEMP-TABLE-PREPARE</code>
        * method of Progress 4GL.
        *
        * @param   name
        *          Temp-table name to be used in subsequent query statements that refer to
        *          this temp-table.
        *
        * @return  {@code true} on success.
        */
       @Override
       public logical tempTablePrepare(String name)
       {
          displayPreparedIgnoring();
          return new logical(false);
       }

       /**
        * Signals that all the field and index definitions for a temp-table have been provided. After
        * the call to this method no fields and indexes can be added to this temporary table.
        * This method is the P2J equivalent of <code>TEMP-TABLE-PREPARE</code>
        * method of Progress 4GL.
        *
        * @param   name
        *          Temp-table name to be used in subsequent query statements that
        *          refer to this temp-table.
        *
        * @return  {@code true} on success.
        */
       @Override
       public logical tempTablePrepare(character name)
       {
          return tempTablePrepare((String) null);
       }

       /**
        * Signals that all the field and index definitions for a temp-table have been provided. After
        * the call to this method no fields and indexes can be added to this temporary table.
        * This method is the P2J equivalent of {@code TEMP-TABLE-PREPARE} method of Progress 4GL.
        *
        * @param   name
        *          Temp-table name to be used in subsequent query statements which refer to this temp-table.
        * @param   before
        *          Create the {@code BEFORE-TABLE} also if {@code true}.
        *
        * @return  {@code true} on success.
        */
       @Override
       public logical tempTablePrepare(String name, boolean before)
       {
          return tempTablePrepare((String) null);
       }

       /**
        * Signals that all the field and index definitions for a temp-table have been provided. After
        * the call to this method no fields and indexes can be added to this temporary table.
        * This method is the P2J equivalent of {@code TEMP-TABLE-PREPARE} method of Progress 4GL.
        *
        * @param   name
        *          Temp-table name to be used in subsequent query statements which refer to this temp-table.
        * @param   before
        *          Create the {@code BEFORE-TABLE} also if {@code true}.
        *
        * @return  {@code true} on success.
        */
       @Override
       public logical tempTablePrepare(String name, logical before)
       {
          return tempTablePrepare((String) null);
       }

       /**
        * Signals that all the field and index definitions for a temp-table have been provided. After
        * the call to this method no fields and indexes can be added to this temporary table.
        * This method is the P2J equivalent of {@code TEMP-TABLE-PREPARE} method of Progress 4GL.
        *
        * @param   name
        *          Temp-table name to be used in subsequent query statements which refer to this temp-table.
        * @param   before
        *          Create the {@code BEFORE-TABLE} also if {@code true}.
        *
        * @return  {@code true} on success.
        */
       @Override
       public logical tempTablePrepare(character name, boolean before)
       {
          return tempTablePrepare((String) null);
       }

       /**
        * Signals that all the field and index definitions for a temp-table have been provided. After
        * the call to this method no fields and indexes can be added to this temporary table.
        * This method is the P2J equivalent of {@code TEMP-TABLE-PREPARE} method of Progress 4GL.
        *
        * @param   name
        *          Temp-table name to be used in subsequent query statements which refer to this temp-table.
        * @param   before
        *          Create the {@code BEFORE-TABLE} also if {@code true}.
        *
        * @return  {@code true} on success.
        */
       @Override
       public logical tempTablePrepare(character name, logical before)
       {
          return tempTablePrepare((String) null);
       }

       /**
        * Returns <code>true</code> if this temp-table is in prepared state (after a successful call
        * to {@link #tempTablePrepare}).
        * This method implements the read-only PREPARED attribute from 4GL.
        *
        * @return  true if operation is successful
        */
       public boolean _prepared()
       {
          return true;
       }

       /**
        * Check whether this TEMP-TABLE is in CLEAR state: I.e. the temp-table is first created or immediately
        * after the CLEAR() method is applied. The other two state of a temp-table are: UNPREPARED and PREPARED.
        * The UNPREPARED state between the first definitional method has been applied and before the
        * TEMP-TABLE-PREPARE() method is applied.
        * <p>
        * This method is FWD-internal. The programmer can check whether the temp-table is in an UNPREPARED or
        * PREPARED state by checking the PREPARED attribute, but the CLEAR state is transparent.
        *
        * @return  Always {@code false} since the static temp-tables cannot be CLEAR-ed.
        */
       public boolean _clear()
       {
          return false;
       }

       /**
        * Obtain the current UNDO attribute of 4GL temp-table.
        *
        * @return  true if the the temp-table can undo.
        */
       @Override
       public logical canUndo()
       {
          if (!valid())
          {
             throw new IllegalStateException("Cannot get UNDO attribute for the static temp table, " +
                   "the table scope is already closed");
          }

          return logical.of(isUndoable());
       }

       /**
        * Returns the temp-table to it's clear state, removing all defined fields and indexes.
        *
        * @return  true if operation is successful
        */
       public logical clear()
       {
          displayCannotClear();
          return logical.FALSE;
       }

       /**
        * Construct an index of this temp-table by adding a new field to it. This method requires
        * the index to be first declared with {@link #addNewIndex} and cannot be called after the
        * {@link #prepared()}.
        *
        * @param   indexName
        *          The name of the index being built.
        * @param   field
        *          The name of the temp-table to be added to the index.
        * @param   ascending
        *          "asc" if the ascending ordering, "desc" for descending other -&gt; error.
        *
        * @return  <code>true</code> for success.
        */
       public logical addFieldToIndex(String indexName, String field, String ascending)
       {
          displayPrepared();
          return logical.UNKNOWN;
       }

       /**
        * Construct an index of this temp-table by adding a new field to it. This method requires
        * the index to be first declared with {@link #addNewIndex} and cannot be called after the
        * {@link #prepared()}.
        *
        * @param   indexName
        *          The name of the index being built.
        * @param   field
        *          The name of the temp-table to be added to the index.
        * @param   ascending
        *          "asc" if the ascending ordering, "desc" for descending other -&gt; error.
        *
        * @return  <code>true</code> for success.
        */
       public logical addFieldToIndex(String indexName, String field, character ascending)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Construct an index of this temp-table by adding a new field to it. This method requires
        * the index to be first declared with {@link #addNewIndex} and cannot be called after the
        * {@link #prepared()}.
        *
        * @param   indexName
        *          The name of the index being built.
        * @param   field
        *          The name of the temp-table to be added to the index.
        * @param   ascending
        *          "asc" if the ascending ordering, "desc" for descending other -&gt; error.
        *
        * @return  <code>true</code> for success.
        */
       public logical addFieldToIndex(character indexName, String field, String ascending)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Construct an index of this temp-table by adding a new field to it. This method requires
        * the index to be first declared with {@link #addNewIndex} and cannot be called after the
        * {@link #prepared()}.
        *
        * @param   indexName
        *          The name of the index being built.
        * @param   field
        *          The name of the temp-table to be added to the index.
        * @param   ascending
        *          "asc" if the ascending ordering, "desc" for descending other -&gt; error.
        *
        * @return  <code>true</code> for success.
        */
       public logical addFieldToIndex(character indexName, String field, character ascending)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Construct an index of this temp-table by adding a new field to it. This method requires
        * the index to be first declared with {@link #addNewIndex} and cannot be called after the
        * {@link #prepared()}.
        *
        * @param   indexName
        *          The name of the index being built.
        * @param   field
        *          The name of the temp-table to be added to the index.
        * @param   ascending
        *          "asc" if the ascending ordering, "desc" for descending other -&gt; error.
        *
        * @return  <code>true</code> for success.
        */
       public logical addFieldToIndex(String indexName, character field, String ascending)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Construct an index of this temp-table by adding a new field to it. This method requires
        * the index to be first declared with {@link #addNewIndex} and cannot be called after the
        * {@link #prepared()}.
        *
        * @param   indexName
        *          The name of the index being built.
        * @param   field
        *          The name of the temp-table to be added to the index.
        * @param   ascending
        *          "asc" if the ascending ordering, "desc" for descending other -&gt; error.
        *
        * @return  <code>true</code> for success.
        */
       public logical addFieldToIndex(String indexName, character field, character ascending)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Construct an index of this temp-table by adding a new field to it. This method requires
        * the index to be first declared with {@link #addNewIndex} and cannot be called after the
        * {@link #prepared()}.
        *
        * @param   indexName
        *          The name of the index being built.
        * @param   field
        *          The name of the temp-table to be added to the index.
        * @param   ascending
        *          "asc" if the ascending ordering, "desc" for descending other -&gt; error.
        *
        * @return  <code>true</code> for success.
        */
       public logical addFieldToIndex(character indexName, character field, String ascending)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Construct an index of this temp-table by adding a new field to it. This method requires
        * the index to be first declared with {@link #addNewIndex} and cannot be called after the
        * {@link #prepared()}.
        *
        * @param   indexName
        *          The name of the index being built.
        * @param   field
        *          The name of the temp-table to be added to the index.
        * @param   ascending
        *          "asc" if the ascending ordering, "desc" for descending other -&gt; error.
        *
        * @return  <code>true</code> for success.
        */
       public logical addFieldToIndex(character indexName, character field, character ascending)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Construct an index of this temp-table by adding a new field to it. The new added filed will
        * sort ascending the table. This method requires the index to be first declared with
        * {@link #addNewIndex} and cannot be called after the {@link #prepared()}.
        *
        * @param   indexName
        *          The name of the index being built.
        * @param   field
        *          The name of the temp-table to be added to the index.
        *
        * @return  <code>true</code> for success.
        */
       public logical addFieldToIndex(String indexName, String field)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Construct an index of this temp-table by adding a new field to it. The new added filed will
        * sort ascending the table. This method requires the index to be first declared with
        * {@link #addNewIndex} and cannot be called after the {@link #prepared()}.
        *
        * @param   indexName
        *          The name of the index being built.
        * @param   field
        *          The name of the temp-table to be added to the index.
        *
        * @return  <code>true</code> for success.
        */
       public logical addFieldToIndex(character indexName, String field)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Construct an index of this temp-table by adding a new field to it. The new added filed will
        * sort ascending the table. This method requires the index to be first declared with
        * {@link #addNewIndex} and cannot be called after the {@link #prepared()}.
        *
        * @param   indexName
        *          The name of the index being built.
        * @param   field
        *          The name of the temp-table to be added to the index.
        *
        * @return  <code>true</code> for success.
        */
       public logical addFieldToIndex(String indexName, character field)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Construct an index of this temp-table by adding a new field to it. The new added filed will
        * sort ascending the table. This method requires the index to be first declared with
        * {@link #addNewIndex} and cannot be called after the {@link #prepared()}.
        *
        * @param   indexName
        *          The name of the index being built.
        * @param   field
        *          The name of the temp-table to be added to the index.
        *
        * @return  <code>true</code> for success.
        */
       public logical addFieldToIndex(character indexName, character field)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds fields from another table into this temp-table. The fields that are already in the
        * temp-table are ignored.
        * This is the P2J implementation of the ADD-FIELDS-FROM of 4GL.
        *
        * @param   hbuf
        *          A handle to a buffer or table from which to copy the field definitions.
        *
        * @return  <code>true</code> for success.
        */
       public logical addFieldsFrom(handle hbuf)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds fields from another table into this temp-table. The fields that are already in the
        * temp-table are ignored.
        * This is the P2J implementation of the ADD-FIELDS-FROM of 4GL.
        *
        * @param   hbuf
        *          A handle to a buffer or table from which to copy the field definitions.
        * @param   except
        *          A comma-separated list of field names to be excluded from the copy process.
        *
        * @return  <code>true</code> for success.
        */
       public logical addFieldsFrom(handle hbuf, String except)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds fields from another table into this temp-table. The fields that are already in the
        * temp-table are ignored.
        * This is the P2J implementation of the ADD-FIELDS-FROM of 4GL.
        *
        * @param   hbuf
        *          A handle to a buffer or table from which to copy the field definitions.
        * @param   except
        *          A comma-separated list of field names to be excluded from the copy process.
        *
        * @return  <code>true</code> for success.
        */
       public logical addFieldsFrom(handle hbuf, character except)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds fields from another table into this temp-table. The fields that are already in the
        * temp-table are ignored.
        * This is the P2J implementation of the ADD-FIELDS-FROM of 4GL.
        *
        * @param   tableName
        *          The name of the table from which to copy the field definitions.
        *
        * @return  <code>true</code> for success.
        */
       public logical addFieldsFrom(String tableName)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds fields from another table into this temp-table. The fields that are already in the
        * temp-table are ignored.
        * This is the P2J implementation of the ADD-FIELDS-FROM of 4GL.
        *
        * @param   tableName
        *          The name of the table from which to copy the field definitions.
        *
        * @return  <code>true</code> for success.
        */
       public logical addFieldsFrom(character tableName)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds fields from another table into this temp-table. The fields that are already in the
        * temp-table are ignored.
        * This is the P2J implementation of the ADD-FIELDS-FROM of 4GL.
        *
        * @param   tableName
        *          The name of the table from which to copy the field definitions.
        * @param   except
        *          A comma-separated list of field names to be excluded from the copy process.
        *
        * @return  <code>true</code> for success.
        */
       public logical addFieldsFrom(String tableName, character except)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds fields from another table into this temp-table. The fields that are already in the
        * temp-table are ignored.
        * This is the P2J implementation of the ADD-FIELDS-FROM of 4GL.
        *
        * @param   tableName
        *          The name of the table from which to copy the field definitions.
        * @param   except
        *          A comma-separated list of field names to be excluded from the copy process.
        *
        * @return  <code>true</code> for success.
        */
       public logical addFieldsFrom(character tableName, character except)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Adds fields from another table into this temp-table. The fields that are already in the
        * temp-table are ignored.
        * This is the P2J implementation of the ADD-FIELDS-FROM of 4GL.
        *
        * @param   tableName
        *          The name of the table from which to copy the field definitions.
        * @param   except
        *          A comma-separated list of field names to be excluded from the copy process.
        *
        * @return  <code>true</code> for success.
        */
       public logical addFieldsFrom(String tableName, String except)
       {
          displayPrepared();
          return new logical();
       }

       /**
        * Obtain the handle to the buffer that was created by default for this temporary table. Every
        * dynamic temp-table is created with at least one buffer. This buffer's object handle is
        * returned by this method.
        *
        * Note that it cannot be called until the table has been prepared using
        * <code>tempTablePrepare()</code> method.
        *
        * This method is the P2J equivalent of <code>DEFAULT-BUFFER-HANDLE</code>
        * attribute.
        *
        * @return  The default buffer handle for the temporary table.
        */
       public handle defaultBufferHandle()
       {
          return new handle(defaultBufferHandleNative());
       }

       /**
        * Obtain the buffer that was created by default for this temporary table. Every
        * dynamic temp-table is created with at least one buffer. This buffer object is
        * returned by this method.
        *
        * Note that it cannot be called until the table has been prepared using
        * <code>tempTablePrepare()</code> method.
        *
        * This method is the P2J equivalent of <code>DEFAULT-BUFFER-HANDLE</code>
        * attribute.
        *
        * @return  The default buffer for the temporary table.
        */
       public Buffer defaultBufferHandleNative()
       {
          if (!valid())
             throw new IllegalStateException("Cannot get default buffer handle for the static temp " +
                                                "table, the table scope is already closed");

          return defaultBuffer;
       }

       /**
        * Checks  whether the resource is dynamic or static.
        *
        * @return   <code>true</code> if the resource is dynamic, <code>false</code> otherwise.
        */
       public logical dynamic()
       {
          return new logical(_dynamic());
       }

       /**
        * Conversion of DYNAMIC attribute. Returns <code>true</code> if the buffer is dynamic.
        *
        * @return   <code>true</code> if the resource is dynamic, <code>false</code> otherwise.
        */
       public boolean _dynamic()
       {
          return false;
       }

       /**
        * Set code page supplier for the specified CLOB field.
        *
        * @param   property
        *          The ORM property name of the CLOB field.
        * @param   supplier
        *          The code page supplier of the specified CLOB field.
        */
       public void setCodePageSupplier(String property, Supplier supplier)
       {
          if (codePagesSuppliers == null)
          {
             codePagesSuppliers = new HashMap<>();
          }

          codePagesSuppliers.put(property, supplier);
       }

       /**
        * Set code page for the specified CLOB field.
        *
        * @param   property
        *          The ORM property name of the CLOB field.
        * @param   codePage
        *          The code page of the specified CLOB field.
        */
       @Override
       public void setCodePage(String property, String codePage)
       {
          if (codePages == null)
          {
             codePages = new HashMap<>();
          }

          codePages.put(property, codePage);
       }

       /**
        * Get code page of the specified CLOB field.
        *
        * @param   property
        *          The ORM property name of the CLOB field.
        *
        * @return  the code page of the specified CLOB field or {@code null} if not configured so the default must
        *          be used.
        */
       @Override
       public String getCodePage(String property)
       {
          if (codePages == null)
          {
             return null;
          }

          return codePages.get(property);
       }

       /**
        * Get code page supplier of the specified CLOB field.
        *
        * @param   property
        *          The ORM property name of the CLOB field.
        *
        * @return code page supplier of the specified CLOB field.
        */
       public Supplier getCodePageSupplier(String property)
       {
          if (codePagesSuppliers == null)
          {
             return null;
          }

          return codePagesSuppliers.get(property);
       }

       /**
        * Reports if this object is valid for use.
        *
        * @return   <code>true</code> if we are valid (can be used).
        */
       public boolean valid()
       {
          return defaultBuffer != null;
       }

       /**
        * Returns a JSON representation of the object.
        *
        * @return JSON representation of the object, or any error that occurred.
        */
       public String toString()
       {
          String myName = (name == null) ? "unnamed" : name;
          String staticName = "STATIC " + myName + ", ID " + getUniqueID().getValue();
          String resultString;
          ObjectMapper objectMapper = new ObjectMapper();
          Map<String, Object> jsonObject = new HashMap<>();
          Map<String, Object> tableData = new HashMap<>();
          RecordBufferSerializer recordBufferSerializer = new RecordBufferSerializer(defaultBuffer.buffer());
          try
          {
             tableData.put(myName, recordBufferSerializer.sqlTableContent());
             jsonObject.put(staticName, tableData);
             resultString = objectMapper.writeValueAsString(jsonObject);
          }
          catch (PersistenceException | SQLException e)
          {
             LOG.severe("Error getting data: " + e.getMessage());
             resultString = "{\"error\": \"Error getting data: " + e.getMessage() + "\"}";
          }
          catch (JsonProcessingException e)
          {
             LOG.severe("JSON processing error: " + e.getMessage());
             resultString = "{\"error\": \"Error generating JSON\"}";
          }
          return resultString;
       }

       /**
        * Determine if an ADD-* function was called for the table (CLEAR function resets the state).
        * Doesn't makes sense for static tables because they are always in prepared state.
        *
        * @return always <code>true</code>.
        */
       protected boolean addFunctionWasCalled()
       {
          return true;
       }

       /**
        * Read XML/JSON data from the input source and store it in the just created empty TEMP-TABLE.
        *
        * @param   tableName
        *          table name
        * @param   reader
        *          XML/JSON source reader and table creator.
        *
        * @return  {@code true} on success.
        *
        * @throws  PersistenceException
        *          if there is any error reading or storing XML/JSON data.
        */
       public boolean readTable(String tableName, TableReader reader)
       throws PersistenceException
       {
          throw new PersistenceException("Invalid 'readTable' call for the static table " + tableName);
       }

       /**
        * Worker to be implemented by each resource.  Called by {@link #delete()}.
        *
        * @return   <code>true</code> if the resource was deleted.
        */
       protected boolean resourceDelete()
       {
          if (!implicitDeletion())
          {
             return false;
          }

          TemporaryBuffer defaultBuffer = defaultBuffer();

          if (defaultBuffer.isGlobal() && !defaultBuffer.isDynamic())
          {
             return false;
          }

          if (defaultBuffer.getMasterBuffer() == defaultBuffer && defaultBuffer.hasExplicitBuffers())
          {
             return false;
          }

          deleteAllBuffers();

          defaultBuffer = null;
          return true;
       }

       /**
        * Check if the resource may be implicitly deleted.
        *
        * @return   <code>true</code> if the resource's instantiating procedure is currently being deleted, and
        *           the resource is currently being processed.
        *           <code>true</code> if the {@link #forceDelete} flag is set.
        */
       @Override
       protected boolean implicitDeletion()
       {
          return forceDelete || super.implicitDeletion();
       }

       /**
        * Set the {@link #forceDelete} flag.
        *
        * @param    forceDelete
        *           The new value for this flag.
        */
       void setForceDelete(boolean forceDelete)
       {
          this.forceDelete = forceDelete;
       }
    }