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;
   }
}