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