Salesforce

How to troubleshoot "Attempt to define too many indexes" errors for OpenEdge clients ?

« Go Back

Information

 
TitleHow to troubleshoot "Attempt to define too many indexes" errors for OpenEdge clients ?
URL Name18848
Article Number000120691
EnvironmentProduct: OpenEdge
Version: 10.x, 11.x, 12.x
Product: Progress
Version: 8.x, 9.x
OS: All supported platforms
Question/Problem Description
How to troubleshoot "Attempt to define too many indexes" errors for OpenEdge clients ?
What usually causes "Attempt to define too many indexes" temp-tables ?
Error (40) running an application
Error (14675) running an application
Steps to Reproduce
Clarifying Information
Application uses temp-tables.
Error MessageSYSTEM ERROR: Attempt to define too many indexes. (40)
SYSTEM ERROR: Attempt to define too many indexes for area <area number> database <db name>. (40) (14675)
Defect Number
Enhancement Number
Cause
If error (40) occurs while running an application, rather than while modifying Data Dictionary definitions, the problem is that there are too many temp-tables defined by the application.

Error (14675) replaces error (40) in current releases, and has additional information. Most importantly, when the error is raised for temp-tables it reports the DBI* temp-file as the database name.

Temp-tables are stored in their own database, local to each client session. As with any other Progress database, the temp-table database can only have up to 32,000 indexes defined. The indexes belonging to each temp-table defined by the application will add up to reach this limit.

It is highly unlikely that an application will purposely define so many temp-tables that this limit will be exceeded. Therefore, error (40) / (14675) usually indicates some kind of anomaly. The most typical ones are:
  1. Static temp-tables are defined inside non-persistent procedures that are called synchronously from within a loop that is contained inside an active transaction.  Until the transaction expires, these temp-tables cannot be removed from the DBI file.
  2. Like the previous example, static temp-tables are defined in code run by a program that has a poorly scoped transaction.  This frequently happens when using SHARE-LOCKs on FIND and FOR statements.  The calling procedure inadvertently opens a transaction, within its stack calls hundreds of programs which define temp-tables, until they've exceeded a resource such as max indexes.
  3. Dynamic temp-tables are created by the application and the code does not clean them up properly. Over time, this can lead to hundreds of stray dynamic temp-tables. At some point the limit of 32,000 indexes will be reached, causing error (40) / (14675).
  4. TEMP-TABLEs or DATASETs are passed between procedures using the TABLE-HANDLE or DATASET-HANDLE parameter type.  This causes a deep copy of the object in order to marshal it to the procedure being called.  TABLE-HANDLE and DATASET-HANDLE parameters that are received must EXPLICITLY be deleted, or this will cause the objects to be dereferenced and left in memory.
  5. Static temp-tables are defined inside persistent procedures or classes that are instantiated but not cleaned up properly. As with previous cases, over time there can be hundreds of persistent procedures/class instances in memory, with thousands of temp-table definitions.
  6. Dynamic temp-tables are created automatically by OpenEdge. Even though these TEMP-TABLEs are created by OpenEdge, it is up to the application to clean them up. For further details regarding when OpenEdge creates dynamic TEMP-TABLEs automatically, see Article:
5. An occurrence of error (40) could be due to a OpenEdge defect, if all the above have been positively ruled out.
Resolution
If the troubleshooting steps in this article rule out application problems, search the Progress knowledge base for known OpenEdge defects that may cause error (40) and/or (14675), or contact Progress Technical Support for further assistance.

Troubleshooting error (40) / (14675)

Progress 8.x does not provide support for dynamic temp-tables. Statements referring to this feature do not apply this release.

OpenEdge 11.x and later delay the instantiating of static temp-tables until they are actually used. Depending on how the application code is written, this can delay the occurrence of error 14675. Refer to Article: 1. Investigate whether stray dynamic temp-tables and/or persistent procedures are lingering in memory after their due life expectancy.

One way of achieving this is to add code in a location where according to the application logic there should be no or few dynamic temp-tables and persistent procedures, and produce warnings if the number of dynamic temp-tables or persistent procedures increases. Code examples are provided in the following Articles:
2. In OpenEdge 10.x and later, use extended Client Logging

The following is an example of Client Startup parameters to enable - extended logging of transactions, entry into and exit from ABL procedures, and dynamic temp-table, buffer and query objects:
 
-clientlog <logfilename> -logentrytypes "4GLTrans,4GLTrace,DynObjects.DB:4" -logginglevel 3

This example combines logging for 2 common scenarios:

a. 4GLTrans and 4GLTrace log entry types together at logginglevel 3 :
Can be used to determine which procedures are being executed within a transaction, to isolate if the problem is caused by making numerous synchronous calls to non-persistent procedures which define static temp-tables during a transaction

b. DynObjects.DB log entry type at logginglevel 4 :
Logs the creation and deletion of all dynamic temp-tables used. This information can be used to determine if these operations are explicitly coded or implicitly performed by the AVM.

To expand the logging to cover leaking static temp-tables, add the DynObjects .Class and DynObjects.Other log entry types. Since static temp-tables are scoped to the persistent procedures or class that instantiates them, this will identify the programs being leaked.

In OpenEdge 11.x, consider using the temp-tables log entry type to expose when the temp-tables are instantiated, deleted or emptied
 
-clientlog <logfilename> -logentrytypes "Temp-tables" -logginglevel 4


Corrective Steps

When lingering temp-tables are found, corrective steps depend on the exact nature of the issue.

When dynamic temp-tables created by application code are not cleaned up, add code to do so.

If static temp-tables are defined in non-persistent procedures within a transaction, there are two options (not mutually exclusive):
  1. Adjust the transaction scope so that it is smaller, or limit the number of iterations per transaction. This allows the temp-tables to be cleaned up before the limit is reached.
  2. Rework the non-persistent procedure into a persistent one, moving the logic into an internal procedure of the persistent procedure. This allows a single instance of the temp-table to be reused for multiple iterations of the logic.
If static temp-tables are defined in persistent procedures, modify the application code in one of the following ways (not mutually exclusive):
  1. Ensure that instances of the procedure are deleted after use
  2. Ensure multiple instances of the procedure can use the same instance of the temp-table. A HANDLE field can be added to the temp-table to track which procedure instance owns a record.
  3. Ensure that there is only a single, reusable instance of the procedure
If static temp-tables are defined in classes, modify application code in one of the following ways (not mutually exclusive):
  1. Ensure that there is only a single, reusable instance of the class needed.
  2. Ensure temp-table a static member of the class. A Progress.Lang.Object field can be added to the temp-table to track which class instance owns a record).
  3. Ensure the class instances are deleted when no longer needed, either by making sure no references remain (so the instance can be garbage collected) or by deleting it explicitly with the DELETE OBJECT statement.
Define temp-tables with  NO-UNDO. For further information refer to Article  Error "Attempt to update data exceeding 32000 . (12371)" raised when assigning a value to a variable  

If TABLE-HANDLE and/or DATASET-HANDLE parameters are used when the parameter is not BY-REFERENCE, a deep copy is made in order to marshal the schema and data to the called procedure.  
  • For INPUT and INPUT-OUTPUT *-HANDLE parameters in CALLED procedures you are responsible for deleting the handle reference before the procedure ends.  The AVM is intelligent enough to delay the actual destruction of the object (temp-table or dataset) if the object is also used in an OUTPUT parameter.  This is often done in a FINALLY block.
  • For OUPUT  *-HANDLE parameters you are responsible for deleting them before the calling procedure ends.  The AVM is intelligent enough to delay the actual destruction of the object (temp-table or dataset) if the object is also used in an OUTPUT parameter.  This is often done in a FINALLY block.
Workaround
Notes
Keyword Phrase
Last Modified Date9/29/2021 3:39 PM

Powered by