See: Description
Interface | Description |
---|---|
AssociationSyncher.Helper |
An interface which abstracts a helper API for managing a foreign DMO.
|
Buffer |
Defines the public API for services representing Progress builtin
functions, methods, attributes, and language statements, which operate on
record buffers.
|
BufferField |
Defines the public API for services representing Progress builtin functions, methods,
attributes, and language statements, which operate on fields.
|
BufferHandle |
Defines the public API for the DEFAULT-BUFFER-HANDLE attribute.
|
BufferReference |
Interface which must be implemented by any DMO dynamic proxy object, to
provide the persistence framework access to the backing record buffer.
|
CharacterExpr |
A convenience interface to make a
Resolvable runtime expression which must return a
character result. |
DatabaseManager.DatabaseConfigFetcher |
Interface for a remote object whose purpose is to fetch a local
DatabaseConfig
object and deliver it to the remote caller. |
DataModelObject |
A marker interface which must be extended by any public Data Model Object
(DMO) business interface.
|
DateExpr |
A convenience interface to make a
Resolvable runtime expression which must return a
date result. |
DatetimeExpr |
A convenience interface to make a
Resolvable runtime expression which must return a
datetime result. |
DatetimeTzExpr |
A convenience interface to make a
Resolvable runtime expression which must return a
datetimetz result. |
DecimalExpr |
A convenience interface to make a
Resolvable runtime expression which must return a
decimal result. |
DynamicJoin.ParameterResolver |
An internal API used by this class to abstract the resolution of the
query substitution parameter at query execution time.
|
DynamicLegacyKeyJoin.ParameterResolver |
An internal API used by this class to abstract the resolution of the
query substitution parameters at query execution time.
|
DynamicQueryHelper.QueryProcessor |
Allows to customize the processing of a predicate for generation of the dynamic query.
|
IndexInformation |
Interface which combines Query:INDEX-INFORMATION attribute and Buffer:INDEX-INFORMATION method.
|
Int64Expr |
A convenience interface to make a
Resolvable runtime expression which must return a
int64 result. |
IntegerExpr |
A convenience interface to make a
Resolvable runtime expression which must return a
integer result. |
Joinable |
Query types which can be added as components to
CompoundQuery
must implement this interface. |
LogicalExpr |
A convenience interface to make a
Resolvable runtime expression which must return a
logical result. |
P2JQuery |
The minimal API all query implementations must provide.
|
P2JQuery.Parameter |
Functional interface used with lambda expressions to defer evaluation of certain query
substitution parameter expressions.
|
ParameterFilter |
Filter that handles parameters passed to the query.
|
Persistable |
Defines the API necessary for the persistence framework to manage a Data
Model Object (DMO) instance.
|
Presortable |
Interface implemented by query implementations which support client-side
results sorting.
|
PresortDelegate |
Interface implemented by client-side sort query types which can be used as
delegates for
QueryWrapper instances. |
Presorter.LazyEvaluator |
Interface for the classes which are used for lazy evaluation of the break rows.
|
QueryAssociable |
Defines the public API for legacy 4GL attributes/methods for dealing with an associated query.
|
QueryConstants |
Constants used in association with queries.
|
QueryOffEndListener |
Interface for objects interested in query off-end events.
|
QueryParam |
A marker interface for query parameters which should be resolved
|
RawExpr |
A convenience interface to make a
Resolvable runtime expression which must return a
raw result. |
RecidExpr |
A convenience interface to make a
Resolvable runtime expression which must return a
recid result. |
ResultListHandler |
Declares the pair methods for handling result-lists
CREATE-RESULT-LIST-ENTRY and DELETE-RESULT-LIST-ENTRY.
|
Results |
An abstraction layer between a joinable query implementation and its
results.
|
ResultsProvider |
An interface which must be implemented by classes which provide delegate
Results objects to ResultsAdapter objects. |
RowidExpr |
A convenience interface to make a
Resolvable runtime expression which must return a
rowid result. |
Scrollable |
Query classes which support the concept of scrollable cursors using the
Cursor class must implement this interface. |
Temporary |
Marker interface which must be implemented by DMO implementation classes
whose instances are backed in the database by temporary tables.
|
TempTable |
Declaration of dynamic TEMP-TABLES attributes and methods.
|
UndoStateProvider |
The implementations of this interface manages/holds the UNDO state of an object.
|
XmlData |
Interface which defines legacy methods for temp-table and data set member buffers to consume
and produce XML data.
|
Class | Description |
---|---|
AbstractJoin |
The abstract base class for dynamic and server-side join helpers.
|
AbstractQuery |
Abstract base class for all query implementation classes.
|
AbstractReversible |
Abstract implementation of
Reversible . |
AbstractTempTable |
Abstract base class for static and dynamic temp-table 4GL objects.
|
AdaptiveComponent |
A query component implementation which extends
QueryComponent to store additional
information needed when reverting an adaptive query from preselect to dynamic query mode. |
AdaptiveFind |
An implementation of
AdaptiveQuery which may begin in dynamic
record retrieval mode. |
AdaptiveQuery |
An adaptive, iterating query which first attempts to retrieve its records
in preselect mode, but changes to dynamic record retrieval as necessary.
|
AssociationSyncher |
The abstract base class for subclasses which synchronize either end of a
foreign key association, based upon legacy key properties being changed in
the record on the opposite end of the association.
|
BasicSorter<T extends java.lang.Comparable> |
An implementation of
Comparator , used to sort instances of
Comparable s in ascending or descending order. |
BufferFieldImpl |
Implementation of Progress 4GL BUFFER-FIELD methods and attributes, using a
FieldReference as a delegate worker. |
BufferImpl |
This class implements services representing Progress builtin functions,
methods, attributes, and language statements, which operate on record
buffers.
|
BufferManager |
Manages all record buffers within the current user context.
|
BufferManager.BatchModeData |
Container for batch assign mode information.
|
BufferManager.RefCount |
Reference count object with a mutable counter value, for tracking buffer references to DMOs
currently in use within a Hibernate session.
|
BufferManager.SessionFlusher |
Commitable implementation which tries to flush Hibernate session before
any rollback.
|
BufferManager.UndoData |
Storage mechanism for maps of reversible/undoable actions, keyed by
primary key.
|
BufferType |
Object which describes a
RecordBuffer type. |
ChangeBroker |
A clearing house which notifies interested parties of changes made to
active records within the current client context.
|
ChangeBroker.ListenerSet |
An ordered set of listeners (iterates in the order added to the set), which optionally
links to other sets of listeners up and down the stack of open scopes.
|
CompoundComponent |
A helper container for a query component.
|
CompoundQuery |
A client-side (relative to the database server) implementation of a
multi-table, join query.
|
ConnectionManager |
Manages information about connected databases in the current context.
|
ConnectionManager.ConnectInfo |
Information about a specific database connection (in Progress terms, not JDBC terms).
|
ConnectionManager.MetaConnectionsCleaner |
Container for DB connections which need their meta tables cleaned up.
|
ConversionPool |
A shared pool of
pattern engines used for
runtime conversion of dynamically defined persistence constructs, such as temp-tables and
queries. |
ConversionPool.Results |
Object which holds the objects stored in the pattern engine by its conversion task.
|
Cursor |
Implementation of a query results list scrollable cursor, for queries which
fetch their results dynamically.
|
Database |
A collection of information required to connect to a database, including the database's
physical name, purpose, and the host address (including port) of the P2J server instance which
is the authoritative controller of this database.
|
DatabaseConfig |
Class which encapsulates information necessary to configure a database.
|
DatabaseManager |
Manages configuration for all databases accessed by the current server,
and provides access to Hibernate session factories to create new sessions.
|
DatabaseManager.Context |
A class containing context-specific data.
|
DatabaseManager.DatabaseConfigFetcherImpl |
Concrete implementation of the
DatabaseConfigFetcher interface. |
DatabaseStatistics |
A singleton instance of this class collects database statistics throughout a P2J server's run,
then collates this information into an H2 database as the server is shutting down.
|
DatabaseStatistics.Collector |
Helper class which gathers local query statistics as the server is running, and which
collects global, Hibernate query and second level cache statistics as the server is
terminating.
|
DatabaseStatistics.Collector.Key |
A hashable key comprised of both location information and an HQL string.
|
DatabaseStatistics.DatabaseHelper |
Helper class to manage database operations while storing data to performance statistics
database.
|
DatabaseStatistics.Location |
Helper class which stores location information regarding the construction of a P2J query.
|
DatabaseStatistics.QueryInfo |
Helper class which stores information about the localized execution of HQL queries.
|
DataSorter |
An specialization of
BasicSorter , used to sort instances of
BaseDataType . |
DataSource |
Object which describes an external source from which data is read into a temp-table buffer
or data set member buffer.
|
DataTarget |
Object which describes an external target into which data is written from a temp-table buffer
or data set member buffer.
|
DBUtils |
A collection useful static methods used to support the persistence framework.
|
DirtyDmoStrategy |
An implementation of a custom entity dirtiness strategy for Hibernate.
|
DirtyTempTableHelper |
Helper class which generates and caches SQL phrases to create and drop
temporary tables, and to create indexes in those tables.
|
DMOIndex |
A helper class used during initialization of the persistence service, when
a configuration for a new database needs to be established, or at runtime
to service queries and record buffer objects.
|
DMOIndex.DMOMetadata |
Metadata about a particular DMO implementation class.
|
DMOIndex.MetadataMap |
Mapping of DMO metadata objects by both DMO interface and by DMO
implementation class.
|
DmoPropertyAccessor |
A Hibernate property accessor for data model objects which at the time of writing is slightly
faster than the basic property accessor which uses reflection to invoke DMO getter and setter
methods.
|
DmoPropertyAccessor.Access |
A class containing the ReflectASM
MethodAccess object and information about
method indices and return types used to create accessor objects using shared instances of
MethodAccess . |
DmoPropertyAccessor.DmoGetter |
Implementation of a
Getter which uses assembled bytecode to call a getter method
instead of Java reflection. |
DmoPropertyAccessor.DmoSetter |
Implementation of a
Setter which uses assembled bytecode to call a setter method
instead of Java reflection. |
DmoPropertyAccessor.Key |
Key for
Getter and Setter cache maps. |
DmoProxyPlugin |
A proxy assembler plugin which manages the assembly of indexed DMO getter/setter methods,
for normalized and denormalized implementations.
|
DmoProxyPlugin.IndexedGetterAssembler |
This class assembles an indexed getter method which performs a range check on the index
before calling the proxy's invocation handler.
|
DmoProxyPlugin.IndexedProxyMethod |
A base class for concrete implementations of indexed proxy method assemblers.
|
DmoProxyPlugin.IndexedSetterAssembler |
This class assembles an indexed setter method which performs a range check on the index
before calling the proxy's invocation handler.
|
DMOSorter |
A sorter which orders data model objects (DMOs) according to a list of
sort criteria . |
DMOSorter.FieldWorker |
Helper comparator implementation which compares a particular property of
a DMO, adjusted for sort direction.
|
DMOValidator |
Performs record-level and field-level validation of database records.
|
DynamicConversionHelper |
Base class with common functions for
DynamicQueryHelper and
DynamicValidationHelper . |
DynamicJoin |
An implementation of a natural join helper used by dynamic query types.
|
DynamicLegacyKeyJoin |
An implementation of a natural join helper used by dynamic query types.
|
DynamicQuery |
Abstract base class for query classes which dynamically navigate and
retrieve results, and which must support results list scrolling.
|
DynamicQueryHelper |
Helper class for dynamic query conversion.
|
DynamicQueryHelper.ParametrizedJast |
A container for holding a JAST and its default parameters.
|
DynamicQueryHelper.QueryCacheKey |
Class that keys the already generated JAST trees within the
LFUAgingCache caches of
DynamicQueryHelper . |
DynamicQueryHelper.WorkArea |
Container of context-local data.
|
DynamicTablesHelper |
Helper class for dynamic temporary tables.
|
DynamicTablesHelper.CacheData |
DMO data to be cached for a dynamically defined temp-table.
|
DynamicTablesHelper.CacheKey |
A hashable key that encapsulates the characteristics which uniquely define the structure of
a dynamic temp-table; namely, its field and index definitions.
|
DynamicTablesHelper.CacheKey.IndexKey |
Instances of this class are used to wrap instances of
P2JIndex , for purposes of
producing hash codes suitable for using instances of the enclosing class as hash map
keys. |
DynamicTablesHelper.DMOInfo |
Class which contains information about a dynamically define DMO, including the compiled
interface and implementation classes, and mappings between the legacy and converted fields.
|
DynamicValidationHelper |
Helper class for dynamic validation expressions conversion.
|
DynamicValidationHelper.ValExprCacheKey |
Class that keys the JAST tree generated from the validation expression.
|
DynamicValidationHelper.WorkArea |
Container of context-local data.
|
FieldInfo |
A data structure which stores information about a field, parsed from a field specifier string
during construction.
|
FieldReference |
A readable, writable reference to a buffer field, used in cases where the
field needs to be accessed at some arbitrary point in time after it is
referenced in application code.
|
FilteredResults |
An implementation of the
Results interface which evaluates
one or more client-side where clause expressions per virtual record, to
create a filtered list of records. |
FindQuery |
A convenience adapter for a
RandomAccessQuery . |
ForeignNuller |
A class whose primary purpose is to null out foreign key references to a
DMO from related records, when the DMO is about to be deleted.
|
ForeignNuller.Context |
Context local state maintained for the enclosing class.
|
ForeignNuller.State |
Object which stores a reference to a local DMO and its lock status
before its foreign reference is changed.
|
ForeignResolver |
Resolves records on either end of a foreign key association, based upon
the values of one or more properties in a DMO, where those properties
represent the legacy "foreign key" in the pre-conversion application.
|
HQLBundle |
An assemblage of the various HQL statements, corresponding, reflective
methods, and an index of the runtime query substitution parameters, which
are necessary to satisfy a specific record retrieval request for a random
access query.
|
HQLExpression |
Represents an HQL expression: HQL where clause, HQL statement or HQL snippet.
|
HQLHelper |
Helper class which provides services to random access style queries.
|
HQLHelperCache |
A cache of
HQLHelper objects mapped to a complex key which encompasses the DMO
implementation class, base where clause, Hibernate substitution types, restriction sorting,
foreign key information, and whether or not the query is a project query. |
HQLHelperCache.Key |
HQLHelper hashable lookup key. |
HQLPreprocessor |
A preprocessor for where clauses written in (extended) HQL.
|
HQLPreprocessor.CacheKey |
Instances of this class are used as keys to cache instances of
HQLPreprocessor . |
HQLPreprocessor.PropertyMatch |
Object which contains information about a single comparison of a database property to a
substitution parameter or literal value.
|
IndexHelper |
Helper object to manage database index information.
|
IndexHelper.EntityIndexKey |
A hashable key which encapsulates a DMO entity and a boolean indicating
unique vs.
|
IndexHelper.PropertyKey |
A hashable key which encapsulates a DMO entity and property name.
|
IndexHelper.SortKey |
A hashable key which encapsulates a DMO entity and a sort phrase.
|
InverseSyncher |
Automatically synchronizes both ends of a foreign key association, based
upon changes made to the values of DMO properties which participate in a
legacy foreign key.
|
LegacyFieldNameMap |
This class performs a bi-directional runtime mapping of DMO properties to their associated
(lower case) legacy field names.
|
LocalSyncher |
Automatically synchronizes both ends of a foreign key association, based
upon changes made to the values of DMO properties which participate in a
legacy foreign key.
|
LocalTempTableHelper |
Helper class which generates and caches SQL phrases to create and drop
temporary tables, and to create indexes in those tables.
|
NopPropertyAccessor |
Implementation of a do-nothing
PropertyAccessor . |
NopPropertyAccessor.NopGetter |
Implementation of a do-nothing
Getter . |
NopPropertyAccessor.NopSetter |
Implementation of a do-nothing
Setter . |
ORMHandler |
Class which manages the loading of a Hibernate
Configuration . |
ORMHandler.TableInfo |
Holder for the table info
|
OutputTableCopier |
Class which is registered as a top-level finalizable and copies data in OUTPUT direction
in table parameter case.
|
OutputTableHandleCopier |
Class which is registered as a top-level finalizable and copies data in OUTPUT direction
in table-handle parameter case.
|
P2JField |
Container for DMO field definitions.
|
P2JIndex |
A descriptor of an index, which may be either a Progress index or an
SQL database index.
|
P2JIndexComponent |
Represents a single index component; stores information about the
component's name, sort direction, whether it contains text data, its case
sensitivity, and abbreviated status.
|
ParameterIndices |
A mapping of the active indices in an array of query substitution
parameters, after an HQL where clause has been preprocessed.
|
Persistence |
The central point for fundamental persistence services in the P2J
environment.
|
Persistence.ColumnKey |
A hash key for a unique combination of table and column name.
|
Persistence.QueryKey |
A hash key for a unique combination of HQL, maximum results, and starting row offset.
|
PersistenceFactory |
Factory for
Persistence objects. |
PreselectQuery |
Query which issues an HQL query to the database server and uses a
scrollable database cursor to navigate over the set of results.
|
PreselectQuery.TemplateResults |
Special
Results implementation for template records. |
PresortCompoundQuery |
PresortCompoundQuery is used when it is necessary to presort the results
of a multi-table join, where the join cannot be performed at the database
server.
|
PresortCompoundQuery.CursorResults |
An implementation of the
Results interface which is backed
by a dynamic Cursor object. |
Presorter |
This helper class performs client-side (i.e., relative to the database
server) sorting of a result set on behalf of a query.
|
Presorter.SortHelper |
A helper object which provides services related to sorting and break
groups.
|
PresortQuery |
A specialized preselect query which uses one or more instances of
Resolvable provided by business application code to sort the
result set returned by the database. |
ProgressiveResults |
An implementation of the
Results interface which is backed by
Results sets of progressively increasing size. |
ProgressiveResults.Locator |
A descriptor object used to locate results brackets and store
information used to access them.
|
PropertyDefinition |
Container for a DMO property's metadata: name, type and extent.
|
PropertyHelper |
Helper class which uses introspection to manage maps of different categories of DMO property
related methods and metadata: getters, setters, extent sizes, and lazy collection
initializers.
|
QueryComponent |
A helper container for a query component.
|
QueryComponent.ServerJoinData |
Information required to create a server-side join between two tables.
|
QueryWrapper |
A delegating container implementation for
AbstractQuery s. |
QueryWrapper.DefaultDelegate |
A no-op implementation of
P2JQuery which is used as the
default delegate for the enclosing QueryWrapper . |
RandomAccessQuery |
The backing query for converted queries which require a dynamic record
retrieval semantic.
|
RecordBuffer |
A container for a Data Model Object (DMO) instance which represents a
single database record (or the lack thereof).
|
RecordBuffer.DatumAccess |
Information needed by a getter or setter method to affect the datum of one property (or one
element within an extent property), namely, the property's name and optional extent index,
if accessing a single element in an extent property.
|
RecordBuffer.ScopeBufferName |
Container immutable class that holds temporarily data needed for restoring a buffer's name
configuration.
|
RecordIdentifier |
A combination of database table name and record ID (primary key), which
uniquely identifies a database record.
|
RelationInfo |
A descriptor object for a primary/foreign key relation between two tables.
|
RelationInfo.PropertyData |
Container object for data which defines a local/foreign property pair.
|
RepositionCache |
A cache which logically maps arrays of primary key IDs to query result set
row numbers.
|
RepositionCache.Node |
Internal data structure which represents a single record ID and an
associated result set row index for the virtual, composite row
containing that record.
|
ResultsAdapter |
An implementation of the
Results interface which delegates
all work to another Results implementation. |
Reversible |
Abstract base class of various types of database actions that must be
reversible.
|
RuntimeJastInterpreter |
This class interprets a JAST tree.
|
SavepointReversible |
Common reversible based on java.sql.Savepoint interface.
|
ScrollingResults |
A simple, scrolling implementation of the
Results
interface, which offers a thin layer around the internal,
ScrollableResults object provided by the query. |
SequenceManager |
A class that manages all sequence handling functions and statements calls,
including static dynamic forms.
|
ServerJoin |
An implementation of a natural join helper used by query types which
perform the join on the database server.
|
ServerLegacyKeyJoin |
An implementation of a natural join helper used by query types which
perform the join on the database server.
|
SimpleResults |
A simple implementation of
Results which stores row data in a
list provided to the constructor. |
SortCriterion |
An individual sort criterion, consisting of a property name, sort
direction, DMO implementation class associated with an alias qualifier,
getter method for the property, and a flag indicating whether case is
ignored when sorting a
character property. |
SortCriterion.CacheKey |
Key for cached criterion lists.
|
SortIndex |
An object which indicates the type of sort used for a particular query,
without regard for sort direction (ascending or descending).
|
StaticTempTable |
Static 4GL temp-table object.
|
TableIdentifier |
A combination of database table name and special identifier, which uniquely identifies
a database record or table as whole.
|
TableMapper<K> |
This class performs a bi-directional runtime mapping of DMO implementation classes (permanent
or temporary) to their associated legacy table name.
|
TableMapper.DynamicTempTableMapper | |
TableMapper.LegacyFieldInfo |
A container with a field's legacy and DMO property name and field attributes.
|
TableMapper.LegacyIndexComponentInfo |
A container with an index component information.
|
TableMapper.LegacyIndexInfo |
A container with a index information, holding index attributes and components.
|
TableMapper.LegacyTableInfo |
A container with the legacy info for a table.
|
TableMapper.PermanentTableMapper |
Mapper for permanent tables.
|
TableMapper.StaticTempTableMapper | |
TableMapper.TempTableMapper |
Mapper for temporary tables.
|
TableResultSet |
Provides the main mechanism of passing table-like metadata and data which the remote side will
interpret as a temporary table.
|
TableSignature |
Records the structure of a table in a manner that can be compared, serialized and
deserialized.
|
TableWrapper |
Any
TableResultSet instance will be wrapped in a TableWrapper instance before
sending it to a remote side. |
TempLock |
Object which encapsulates a resettable lock on a specific DMO.
|
TemporaryBuffer |
A specialized record buffer implementation which uses a temporary table
as backing storage and supports Progress' temp/work-table semantics.
|
TemporaryBuffer.Context |
Helper which tracks the multiplex IDs currently in use by DMO interface
in the current client context, as well as the reference count of temp
tables created in the database using the context's current connection,
and domains of master/slave buffers.
|
TemporaryBuffer.DefaultUndoState |
A class that holds the default UNDO attibute for a TEMP-TABLE.
|
TempTableBuilder |
Implementation of buffer of a dynamic TEMP-TABLE and the associated
attributes and methods.
|
TempTableConnectionProvider |
A specialized connection provider which ensures that a database connection
used to create temp tables is preserved until the last temp table in use
is dropped.
|
TempTableConnectionProvider.Context |
An instance of this class is created for each client context, in order
to manage connection data specific to that context.
|
TempTableHelper |
Abstract helper class which generates and caches SQL phrases to create and
drop temporary tables, and to create indexes in those tables.
|
TempTableHelper.TableMapping |
Implementation of Hibernate's internal
Mapping interface,
required when generating dialect-specific, SQL create temp table
statements. |
TempTableResultSet |
Implements a method of serializing the metadata and the full data of a temp-table, specified
by a
temp-table DMO . |
UnpooledConnectionProvider |
A simplified implementation of Hibernate's
ConnectionProvider
interface which does no connection pooling, but instead fetches a new JDBC
connection each time UnpooledConnectionProvider.getConnection() is invoked, and closes that
connection each time UnpooledConnectionProvider.closeConnection(java.sql.Connection) is invoked. |
ValidationData |
This object stores validation parameters to assist the
DMOValidator
during record validation. |
Enum | Description |
---|---|
AbstractTempTable.CallingFunction |
Enumeration which represents some temp-table functions.
|
BufferImpl.FindMode |
The mode for finding (first, last, unique) records in a dynamic call to a buffer handle.
|
ConversionProfile |
An enumeration of conversion configuration profiles which can be loaded and performed by the
pattern engine at runtime to convert dynamic temp-tables and queries.
|
Database.Type |
Type/purpose of database
|
FindQuery.CanFind |
Types of can-find lookups
|
OffEnd |
An enumeration of the various query off-end states:
not off-end
off the front end of a result list
off the back end of a result list
|
RecordBuffer.MethodType |
Possible method types
|
RecordBuffer.OperationType |
Possible buffer operation types
|
TemporaryBuffer.CopyTableMode |
Table copy mode.
|
Exception | Description |
---|---|
DatabaseConnectionException |
Represents a Progress database connection error.
|
MissingRecordException |
Exception thrown when a database record which is expected to exist cannot
be found.
|
PersistenceException |
This exception is thrown by the persistence service layer to indicate
error conditions having to do with database access and configuration of
the persistence framework.
|
QueryOffEndException |
Exception thrown when certain query instances run off end.
|
RuntimeJastInterpreter.InterpreterException |
Exception thrown within the RuntimeJastInterpreter.
|
ValidationException |
This exception is thrown by the persistence service layer to indicate
DMO record validation failures.
|
Annotation Type | Description |
---|---|
LegacyField |
Annotation definition to mark a DMO property with its legacy field name and attributes.
|
LegacyIndex |
Annotation definition to mark a DMO class with a legacy table index.
|
LegacyIndexComponent |
Annotation definition to mark a DMO class with a legacy table index component (field with
sorting direction).
|
LegacyIndexes |
Annotation definition to mark a DMO class with its legacy indexes.
|
LegacyTable |
Annotation definition to mark a DMO implementation class with its legacy table name.
|
Authors |
Eric Faulhaber Constantin Asofiei |
Date |
June 4, 2009 |
Access Control |
CONFIDENTIAL |
foo
containing a data field bar
will convert roughly to a DMO
class Foo
with a private instance variable bar
,
and public getBar
and setBar
methods
(note: the accessor will be isBar
in the case where
bar
represents a logical
data type).
In actuality, the naming conversions may be more complex than this, in
that arbitrarily granular substitutions and expansions are applied
during the conversion process, which are specific to the application
being converted. This allows for a more verbose DMO class name
(often a compound word), which is typical in the target environment, as
opposed to the often terse, and sometimes cryptic, table and field
names used in the source environment, imposed by historical limitations.persist
package may also use
this identifier directly to retrieve individual records in certain
cases. This unique identifier maps directly to the primary key
value of the backing record in the database. Temp table DMO
classes are slightly more polluted: each additionally contains a
multiplex ID field and implements the Temporary
marker
interface..hbm.xml
instead of .class
(.java
in the source directories). These documents
live alongside their Java counterparts in the same directory inside the
deployment archive (generally a JAR file).schema
package overview.schema
package overview.java.lang.Long
(primary key field/methods);java.lang.Integer
(_multiplex
field for temp table DMOs);java.lang.Integer
(Hibernate type integer
) and java.lang.Long
(Hibernate type long
), the backend database in the
target environment and Hibernate of course are unaware of the P2J
wrapper data types. This is another area where the mismatch
between Progress 4GL semantics and the target environment must be
managed.org.hibernate.usertype.UserType
interface. This provides transparent transitions between the P2J
wrappers needed by the converted application, and the SQL data types
needed by the database. For the custom user type implementations,
we provide a mapping between the P2J wrapper types and the closest
corresponding JDBC data type (defined in the java.sql.Types
class), as follows:Progress Type |
JDBC/SQL
Type |
P2J
Type |
User
Type Implementation |
Notes |
character |
VARCHAR |
character |
CharacterUserType |
User type uses java.lang.String
internally. |
date |
DATE |
date |
DateUserType |
User type uses java.sql.Date
internally. |
decimal |
NUMERIC |
decimal |
DecimalUserType |
User type uses java.math.BigDecimal
internally. |
integer |
INTEGER |
integer |
IntegerUserType |
User type uses int
internally. |
recid | INTEGER | recid | IntegerUserType | User type uses int internally. |
rowid | BIGINT | rowid | RowidUserType | User type uses java.lang.Long internally. |
logical |
BIT |
logical |
LogicalUserType |
User type uses boolean
internally. |
raw |
VARBINARY |
raw |
RawUserType |
User type uses byte[]
internally. |
unknown |
NULL |
n/a |
n/a |
All user type implementations
transparently implement this mapping |
TransactionManager
to map
Progress transaction semantics to SQL transactions. As much
transaction processing as possible has been made transparent to
application code. The persistence layer uses TransactionManager
's
various callback services to determine when a transaction must be
commited or rolled back, and when database resources and record locks
are released.BufferManager
class is created immediately upon the creation of each new user
context. It manages all buffers open in that context. As an
implementor of Scopeable
, BufferManager
is
notified by the TransactionManager each time a new block scope is
opened and again when it is closed. The object is also notified
by each RecordBuffer
instance whenever a new scope is
opened on that buffer. BufferManager
tracks all
open buffer scopes within the local user context. When it
receives notice that a transaction level block has opened, it starts a
new database level transaction for each database currently referenced
by an open buffer scope. When any block opens that is within a
transaction, it registers all open buffers for a commit/rollback
callback.BufferManager
also implements BatchListener
,
so that it can receive notifications about assign batch mode
processing. This mode is used when multiple changes must be made
to one or more DMO objects without triggering validation until the
batch ends. BatchListener.batchNotify
methods
trigger calls to RecordBuffer
's static startBatch
and endBatch
methods.RecordBuffer
class is created each time a buffer is defined in application
code. This object manages all resources associated with a buffer
throughout its lifetime, including any record locks acquired through
that buffer. RecordBuffer
implements Finalizable
and registers with the TransactionManager
each time openScope
is invoked. The context-local ConnectionManager
is
also notified of the buffer scope open event. Upon closing of the
scope, the buffer attempts to transition any record locks acquired by
the buffer during the lifetime of the current scope. This may
mean releasing each lock entirely, or downgrading it to a share lock
from an exclusive lock.RecordBuffer
manages the interaction between DMOs and
Hibernate's Session
object (indirectly, via the Persistence
class), in order to maintain sub-transaction level undo (i.e.,
rollback) capability across nested scopes. For each create,
delete, and load operation which occurs in a RecordBuffer
instance, a RecordBuffer.Reversible
instance is stored
for the current scope. RecordBuffer
implements Commitable
and is registered to receive commit and rollback callbacks by the BufferManager
at each block scope inside a transaction. When a subtransaction
or transaction commit occurs, all Reversible
objects in
the current scope are copied up to the parent scope, to preserve undo
capability at that scope. When a rollback occurs, all Reversible
objects in the current scope have their rollback methods invoked, which
resets the buffer's state to enable a retry.ConnectionManager
class is created the first time it is needed in the current user
context. This is typically during instantiation of the first RecordBuffer
used in that context. This object tracks all connections made to
a physical database, in the sense of Progress
connections (i.e., uses of the CONNECT and DISCONNECT statements in
pre-converted code). This does
not trigger a JDBC connection, since this occurs implicitly when
a transaction is started or when a query is executed. Rather,
this object is used to track references to physical, transient (i.e.,
not configured by default) databases which are dynamically registered
and deregistered by application logic. Connections trigger
transient databases to be registered with the DatabaseManager
,
and disconnections cause them (eventually) to be deregistered.ConnectionManager
implements Finalizable
, and registers itself for master
transaction finish notifications upon construction. Whenever a
transaction scope closes, all pending disconnect requests are honored
and those databases are deregistered with the database if no other
buffers in the current context still reference them.No record in scope | |
NO-LOCK | |
SHARE-LOCK | |
EXCLUSIVE-LOCK |
Example | Notes | |
1 |
|
At line 002, the transaction a record is found with EXCLUSIVE-LOCK, then re-found with NO-LOCK at line 004. However, because we are inside a transaction, the lock is downgraded to SHARE-LOCK here, rather than released. After the transaction ends, the lock is released. |
2 |
|
In this case, the buffer scope of the person buffer is larger than the transaction scope, because it begins at line 001, when the record is found with NO-LOCK. As in the previous example, it is downgraded rather than released at line 005, but the SHARE-LOCK remains even after the transaction ends at line 006. It is not until line 007 that the lock is finally released by the explicit find NO-LOCK statement. |
3 |
|
Even though the buffer scope is larger than the transaction scope in this case, the undo at line 005 causes the lock to revert at the end of the transaction to its state at the beginning of the transaction, NO-LOCK. |
4 |
|
In
this case, the EXCLUSIVE-LOCK is acquired in a repeat block
nested within the transaction scope at line 004. Even though the
repeat block is undone at line 006, the exclusive lock is not released
when the repeat block ends at line 007. It is not until the
transaction exits at line 008 that the lock is released. Note that even though the buffer scope is larger than the transaction scope, the lock is not downgraded to SHARE-LOCK when the transaction ends, unlike Example 2. The existence of the UNDO preempts this behavior and causes the lock instead to revert to its state at the beginning of the transaction, even though it remains at EXLUSIVE-LOCK throughout the remainder of the transaction. Thus, had we initially found the record with SHARE-LOCK at line 001, it would still be locked with SHARE-LOCK at line 008. |
5 |
|
This example is similar to Example 4, however, without the UNDO, the EXCLUSIVE-LOCK is downgraded to SHARE-LOCK at the end of the transaction. It remains SHARE-LOCKED until it is explicitly released at line 009. |
6 |
|
In this case, the buffer scope is smaller than the transaction scope. Even though the record is no longer referenced after the end of the inner repeat loop, it remains locked through the end of the transaction, so that no other session can edit it before the transaction has been committed (or undone). However, the EXCLUSIVE-LOCK is downgraded to a SHARE-LOCK at the end of the buffer's scope. It is released entirely at the end of the transaction. |
LockManager
Java interface
was developed for this purpose. A particular concrete
implementation is created at P2J server initialization;
the implementation class to use is specified in the
directory. The Persistence
class uses the lock manager transparently to do its work;
generally,
the lock manager does not need to be accessed directly by application
level
code. There is one Persistence instance per physical database managed
by a P2J application server. External applications can access a
Persistence instance via remote method calls, or they may implement a
remotable implemenation of the LockManager interface (see below). To date, a
non-Java mechanism does not exist for external access.LockManager
interface
is InMemoryLockManager
.
An instance of this class resides in the server JVM. As the name
suggests, all locking behavior is managed in the internal memory of the
server
process. Thus, coordinated locking is available only to
objects which exist in the JVM server process. To maintain the
integrity of concurrent record access, all lock requests must
be routed
through this object. If locking needs to be shared among external
JVM
instances, one of the mechanisms described above must be employed.
The default mechanism for such coordination among separate P2J
server instances is described below.LockManager
interface: RemoteLockManager
. An instance of this class is automatically created for and used by a specialized Persistence
instance, which is responsible for accessing a remote database. RemoteLockManager
acts as a proxy for the remote server's corresponding, primary LockManager
for the target database: as a method on the RemoteLockManager
instance is invoked, the request is forwarded to the remote server and is handled there by a LockManagerMultiplexer
implementation, which dispatches the request to the appropriate, local LockManager
for the target database. A response is returned to the RemoteLockManager
which initiated the request on the requesting server. Other than
the increased latency to communicate between P2J servers, the use of
the remote LockManager
proxy mechanism is transparent,
and is managed automatically by the P2J runtime environment. This
mechanism presumes a direct, server-to-server connection can be
established between the two P2J servers.RecordLockContext
Java interface. It is intended for use only within the P2J runtime environment, to manage communal locks among RecordBuffer
instances. A no-op implementation is used for temporary tables,
and a package private, inner class implementation is used for permanent
tables. When a RecordBuffer
or query object needs to acquire or release a record lock, it does so through this interface. A RecordLockContext
implementation uses the low level interface to perform the actual lock
operations. This implementation, in collaboration with the
RecordBuffer
class, enforces the lock transition rules specified above.
It is also responsible for ensuring the asymmetric rules of lock
acquisition and release when multiple buffers within a user context
access locks for the same record.RecordBuffer.define
or TemporaryBuffer.define
), the application is
given a proxy to the underlying DMO, rather than a direct
reference.
The proxy's invocation handler (implemented within RecordBuffer
as an
inner class) intercepts mutator method invocations on the DMO and
upgrades the lock from SHARE to EXCLUSIVE if necessary. It is
assumed a transaction is active when such an upgrade is
attempted._temp
, which is reserved
for this purpose. This
circumvents the problem of having to associate temp tables at runtime
with different, existing databases. Whereas regular table DMOs
are
backed by RecordBuffer
instances and are defined with a
call to RecordBuffer.define()
, temp table DMOs are backed
by TemporaryBuffer
instances and are defined with a call
to TemporaryBuffer.define()
. Since TemporaryBuffer
extends RecordBuffer
, they are otherwise used the same
way.Temporary
marker interface;_multiplex
_multiplex
fieldTemporaryBuffer
class for additional details on multiplexing.=
),
or at the end of a buffer
copy operation. If multiple fields are being updated in a
BUFFER-COPY or in an ASSIGN statement, updates to affected indices are
deferred at least
until all fields in the respective statement have been assigned.
As soon as enough assignments have been made so as to have
"touched" all
the fields participating in any index (or group of indices) of the
target table, a snapshot of the new record is made in its current
state, and this "unfinished", placeholder record is inserted into that
index or into those indices. All other indices remain unaffected.
Note that for the placeholder record to be inserted into an
index, it is not necessary that the new values of the assigned fields
be different than their initial, default values; all that is
necessary is the act of assignment itself.Field | Type | Initial Value |
---|---|---|
f1 | integer | 0 |
f2 | integer | 2 |
index idxF1 field f1 | ||
index idxF2 field f2 |
Field f1 | Field f2 |
---|---|
1 | 1 |
3 | 3 |
1 CREATE sample.Session B:
2 f1 = 2.
3 pause.
4 f2 = 2.
5 pause.
6 f2 = 7.
1 FIND FIRST sample WHERE f1 = 2 USE-INDEX idxF1 NO-LOCK NO-ERROR.Assume session A runs through line 2 and pauses at line 3. At this point, a new sample record has been created and only field
2 FIND FIRST sample WHERE f2 = 2 USE-INDEX idxF2 NO-LOCK NO-ERROR.
3 pause.
4 FIND FIRST sample WHERE f2 = 2 USE-INDEX idxF2 NO-LOCK NO-ERROR.
5 pause.
6 FIND FIRST sample WHERE f2 = 7 USE-INDEX idxF2 NO-LOCK NO-ERROR.
7 IF AVAILABLE sample
8 THEN MESSAGE "Found sample record where f2 = 7; f1:" f1 ", f2:" f2.
f1
has been assigned. The new sample record has a value of 2 in field f1
(explictly assigned), and a value of 2 in field f2
(initial, default value). If the code in session B is now run,
the FIND statement in line 1 will find a snapshot of the newly created
record in session 1. The FIND statement in line 2 will not find a
record, even though the default value of field f2
matches the search criteria. This is because the assignment in line 2 of session A only has updated index idxF1
so far. Index idxF2
has not yet been updated to reflect the presence of the new record.f2
's value as 2 (the same value it already had as its initial value), index idxF2
is now updated. If the FIND statement in line 4 of session B is executed, it will find the new record's snapshot.idxF2
again. Now, session B is allowed to continue through line 8.
Line 6 in session B will find the new record's snapshot.
However, the message which is printed at line 8 will look like:Found sample record where f2 = 7; f1: 2 , f2: 2Note that -- even though the new record was found in session B using the criterion
f2 = 7
-- session B will not be aware of the new value (7) of f2
,
assigned in line 6 of session A. Only the data which were in the
new record at the moment the snapshot was made (that is, at the moment
the first index was modified in session A, line 2), are visible from
other sessions. Subsequent updates to the new record are not
visible in other sessions until the new record is flushed to the
database and the enclosing transaction is committed; however,
insofar as any updates made in session A which change the location of
the new record in any index on the sample table, those index updates
will change where and if the new record can be found in other sessions.INSERT | UPDATE | DELETE | |
|
|
|
Deleted record can no longer be retrieved. |
|
Inserted record not available to second session. | Record update affects neither record retrieval nor data visibility in second session. | Deleted record can no longer be retrieved. |
dmo_oper.p
and in session 2 the driver program dmo_test.p
. lock: share-lock; exclusive-lock;
statements: repeat preselect; query preselect; query preselect scrolling; do preselect
statements type: without where; use-index; where indexed; where not indexed;
lock: share-lock; exclusive-lock;
statements: query for; query for scrolling; for each;
statements type: without where; use-index; where indexed; where not indexed;
lock: no-lock
statements: repeat preselect; query for; query for scrolling; query preselect; query preselect scrolling;
statements type: without where;
lock: no-lock
statements: do preselect each;
statements type: without where; use-index; where indexed; where not indexed;
lock: no-lock
statements: repeat preselect; query for; query for scrolling; for each;
statements type: use-index; where indexed;
lock: no-lock
statements: repeat preselect; query for; query for scrolling; for each;
statements type: where not indexed;
lock: share-lock; exclusive-lock;
statements: query for; query for scrolling; for each;
statements type: use-index; where indexed;
lock: share-lock; exclusive-lock;
statements: query preselect; repeat preselect; do preselect;
statements type: without where; use-index; where indexed; where not indexed;
lock: no-lock
statements: query for; query for scrolling; for each;
statements type: without where; use-index; where indexed; where not indexed;
lock: no-lock
statements: query preselect; repeat preselect; do preselect;
statements type: without where; use-index; where indexed; where not indexed;
statements: repeat preselect each; query preselect; query preselect scrolling; do preselect each;
statements type: without where, use-index, where indexed, where not indexed
locks: share-lock, exclusive-lock
statements: repeat preselect last; for last; do preselect last;
statements type: without where
locks: share-lock, exclusive-lock
statements: query for; query for scrolling; for each;
statements type: without where, use-index, where indexed, where not indexed
locks: share-lock, exclusive-lock
statements: repeat preselect first; for first; do preselect first;
statements type: without where
locks: share-lock, exclusive-lock
statements: repeat preselect each; repeat preselect first; repeat preselect last; query for; query for scrolling; query preselect; query preselect scrolling; for each; for first; for last; do preselect first; do preselect last;
statements type: without where
locks: no-lock
statements: do preselect each;
statements type: without where
locks: no-lock
statements: query for; query for scrolling; for each; do preselect each;
statements type: without where, use-index, where indexed, where not indexed
locks: share-lock, exclusive-lock
statements: repeat preselect each; query preselect; query preselect scrolling;
statements type: without where, use-index, where indexed, where not indexed
locks: share-lock, exclusive-lock
statements: do preselect each;
statements type: without where, use-index, where indexed, where not indexed
locks: no-lock
statements: query for; query for scrolling; for each;
statements type: without where, use-index, where indexed, where not indexed
locks: no-lock
statements: repeat preselect each; query preselect; query preselect scrolling; do preselect each;
statements type: without where, use-index, where not indexed
locks: share-lock, exclusive-lock
statements: repeat preselect first; repeat preselect last; query for; query for scrolling; for each; for first; for last; do preselect first; do preselect last;
statements type: without where, use-index, where indexed, where not indexed
locks: share-lock, exclusive-lock
statements: repeat preselect each; query preselect; query preselect scrolling; do preselect each;
statements type: where indexed
locks: share-lock, exclusive-lock
statements: repeat preselect first; repeat preselect last; query for; query for scrolling; query preselect; query preselect scrolling; for each; for first; for last; do preselect first; do preselect last;
statements type: without where, use-index, where indexed, where not indexed
locks: no-lock
statements: query for; query for scrolling; for each;
statements type: without where, use-index, where indexed, where not indexed
locks: no-lock
statements: repeat preselect each; do preselect each;
statements type: without where, use-index, where indexed, where not indexed
locks: no-lock
statements: repeat preselect each; query preselect; query preselect scrolling;
statements type: without where, use-index, where indexed, where not indexed
locks: share-lock, exclusive-lock
statements: query for; query for scrolling; for each; do preselect each;
statements type: without where, use-index, where indexed, where not indexed
locks: share-lock, exclusive-lock
statements: repeat preselect each; query for; query for scrolling; query preselect; query preselect scrolling; for each;
statements type: without where, use-index, where indexed, where not indexed
locks: no-lock
statements: do preselect each;
statements type: without where, use-index, where indexed, where not indexed
locks: no-lock
DirtyShareManager
manages access to each dirty database instance and its supporting data
structures. There is one such object per primary, permanent
database instance. It is this object which executes queries,
inserts, and updates against the dirty database when information about
uncommitted transaction state in the corresponding, primary database
must be shared. This object lazily creates tables in the dirty
database as needed. Each such table mirrors the structure of its
corresponding relation in the primary database, including indexes,
except that no index (save the surrogate primary key index) is unique,
even if its analog is unique in the primary database. This
enables the P2J runtime to detect potential unique constraint
violations safely, without triggering an actual error in the dirty
database. Only information about uncommitted inserts of new
records and updates of new or existing records is maintained inside the
dirty database. Information about uncommitted record deletes is
maintained in separate data structures, within the dirty share manager
implementation.DirtyShareContext
, one per primary database instance. This DirtyShareContext
instance is that session's access point to the associated DirtyShareManager
.
When a session needs information about uncommitted state in other
sessions, or needs to share information about its own uncommitted
state, it does so using the DirtyShareContext
API. A DefaultDirtyShareContext
implementation coordinates with the appropriate DirtyShareManager
implementation object for permanent tables. A NopDirtyShareContext
implementation, whose methods generally do nothing and return quickly,
is used for temporary tables. This choice was made to avoid
having to write and maintain specialized runtime code specifically for
temporary tables in many places, since so much of the runtime is common
for permanent and temporary tables.DirtyShareContext
instance for that database will coordinate with a special implementation of the DirtyShareManager
interface: RemoteDirtyShareManager
. RemoteDirtyShareManager
acts as a local proxy to the remote database's DirtyShareManager
instance. All requests are executed over the network to the
remote server, where they are serviced by the appropriate dirty share
manager. The remote nature of a database and any dirty sharing
done with respect to that database is thus logically transparent to the
requesting session.HQLPreprocessor
analyzes each where clause and determines which types of DMOs must have
their uncommitted changes leaked when the associated query is
executed. RandomAccessQuery
and PreselectQuery
use this information to trigger the dirty share manager to update its
snapshots of the associated, modified records in the current session
via DirtyShareContext.updateSnaphots(List<String>, Persistence)
, effectively publishing these uncommitted updates to all sessions.RecordBuffer
and certain query classes that contain it manage when validation occurs.RecordBuffer$ValidationHelper
manages what needs to be validated.DMOValidator
manages how validation occurs.RecordBuffer.endBatch()
).
Finally, a converted BUFFER-COPY statement will update multiple
(potentially all) of a DMO's properties. Again, validation of the
changes to the destination DMO is deferred until all targeted
properties are copied.RecordBuffer.validate(DataModelObject)
method explicitly. This triggers full validation of the target DMO.ValidationHelper
inner class of RecordBuffer
manages the state which tracks which properties and unique constraints have been validated and which still require validation.RecordBuffer
determines a particular level of validation is necessary, it uses the ValidationHelper
to prepare a ValidationData
instance. This object contains metadata about the validation to be performed. ValidationHelper
passes this object to an instance of DMOValidator
. One instance of DMOValidator
is created for each DMO type. These instances are immutable and
stateless (with respect to any discreet validation operation, at
least). As such, they can be shared across user contexts and are
thus created lazily and cached in a static map by DMO type. The DMOValidator
interrogates the ValidationData
object to determine which nullability and unique constraints must be checked.ValidationException
to be thrown, which is caught by the calling RecordBuffer
and reported to the user as an error.ValidationException
is thrown. If all checks pass, the change is immediately flushed
to the database. This flushing and checking is synchronized
at an index level, so that only one user context can be updating an
index at a time. It is also at this stage (for permanent tables)
that index changes are shared with other sessions via the dirty share manager.Relation |
DMO Instance Member |
many-to-one; "many" end represents the "foreign" end of the relation | DMO on "many" end stores direct
reference to DMO at the "one" end of the relation |
one-to-many; "many" end represents the "foreign" end of the relation | DMO on "one" end stores a Set
of DMOs at the "many" end of the relation |
one-to-one; conversion hint determines "foreign" end of the relation | DMO on either end stores direct
reference to DMO at the opposite end of the relation |
<record> of <table>
join
construct must be supported by the use of foreign keys;P2JQuery
implementations support the use of an inverse
DMO, either at query construction, or when adding a component to a
multi-table query. The inverse
parameter represents
the DMO instance on the other end of the foreign relation which defines
the natural join. When such a parameter is provided to a query,
the persistence runtime does the necessary work behind the scenes to
execute an ANSI-style join between the necessary tables using foreign
keys. Calling code needs to provide the inverse
parameter to a query constructor or to an addComponent()
method variant, but the natural join query support is otherwise
transparent to application code.RecordBuffer
class.dmo_index.xml
file for the application, specifically in the path dmo-index/schema/class/foreign/property/
.
This document is created during application conversion and is read by
the persistence framework at P2J server initialization.AssociationSyncher
class does the
grunt work of foreign key synchronization. At defined points
(after a batch assignment of property values, or upon the assignment of
a single property if not in batch assign mode), this class will query
the database for the foreign record which matches the new property
value (or set of new values), and update the appropriate instance
member in the current buffer record with the DMO, if any, found.
When this change is flushed to the database, Hibernate automatically
updates the associated foreign key.com.goldencode.p2j.persist.pl
package
description.Wrapper
Type |
Feature |
Notes |
com.goldencode.p2j.util.character |
Case sensitivity |
Case sensitivity is an attribute
of the P2J character class. However, server-side
database functions currently use java.lang.String as the
data type for parameters and return types where a text value is
needed. Thus, all text comparison operations which occur
internally within the database function will be case sensitive.
For case-insensitive comparisons, this issue usually can be
circumvented by uppercasing text parameters in the HQL expression as
necessary, before they are passed to the database function.
However, functions whose work relies upon querying or setting this
attribute internal to the function implementation will not necessarily
behave correctly. Functions must therefore be reviewed on a case
by case basis to determine whether such a dependency exists. |
com.goldencode.p2j.util.decimal |
Precision |
The P2J implementation of decimal
uses a default precision value of 10 places after the decimal
point. However, server-side database functions currently used
java.lang.Double as the data type for parameter and return types where
a non-integral, numeric value is needed. Thus, database function
parameters which use a non-default precision setting currently
disqualify a particular function or operator instance from converting
to a server-side database function. Likewise, database functions
which set the precision value to a non-default value cannot be
converted to server-side functions. |
com.goldencode.p2j.util.date |
Timezone |
The P2J implementation of date
is timezone-neutral by default. If a where clause expression
requires a specific timezone setting for a function parameter or for an
operand of a logical or arithmetic operation, the subexpression
containing that function call or operation currently cannot be
converted to a server-side database function. |
persist
package includes the WhereExpression
class. Each query type in the persist
package
allows one (or multiple, for some types) WhereExpression
instance to be registered with the query. Where clauses in the
pre-conversion application are analyzed during conversion. All
components of the where clause which can be executed at the database
server are distilled into an HQL where clause. Those which
require client-side where clause processing result in an anonymous WhereExpression
subclass being defined as an instance variable within the converted
program's Java class. This conversion implementation is designed
to minimize the number of records brought back to the P2J server for
client-side testing, by maximizing the restriction which occurs at the
server. However, this is not always possible and in the worst
case scenario will result in every record in a table being returned to
the P2J server for client-side testing, in the case where no HQL
expression can be distilled from the original where clause.java.sql.Date
is actually a time and date value rolled into one, including a
particularly confusing implementation of timezones, which may have
implications on the use of dates in the persistence runtime. The
most obvious problem from a runtime perspective is the mismatch of
valid date ranges supported by different database vendors, which
creates the possibility that we will encounter dates within a query's
where clause which are supported by Progress (and Java), but may be out
of bounds (i.e., too early or too late) for a particular backend.SQLException
.
Therefore, we cannot allow out of bounds dates to be sent to the
backend. This problem may occur both with dates which are used as
query substitution parameters, as well as date literals which are
embedded directly in the where clause text. The former issue has
been addressed by clipping query substitution parameter dates
which are invalid (i.e., too early or too late) with regard to the
range of dates supported by the backend database's date type. The
latter issue remains unaddressed; in this case, a different
approach will be necessary, probably
involving some advanced analysis by the HQLPreprocessor
.com.goldencode.p2j.util.date
, we check whether its value
is outside the
range supported by the backend implementation. If so, we reset
the
value to the closest possible date supported by the backend. A
debug message (level FINE) is
logged whenever such a substitution is made.com.goldencode.p2j.persist.dialect.P2JDialect
,
to match the implementation of com.goldencode.p2j.util.date
....where my_date >= ? and
my_date <=
?
). However, it may cause a change in behavior for
equality and
inequality matches (e.g., ...where my_date = ?
). We
chose to log the message at level FINE, rather than
WARNING. In cases where the substitution is necessary, it may
occur
quite often, particularly for dynamic queries executed within a loop.
Thus, the cost of composing and logging the message
repeatedly would become significant in a production environment.
Therefore, it should be noted that this higher level of log filtering
may mask an unintended change in query behavior, which may only be
detectable by its subtle side effects (missing records, too many
records found, etc.). We
deemed this risk to be minimal, since it would be unusual for a
business application to rely upon date processing outside the date
ranges supported by most modern database implementations.