Class IdentifierGenerator

java.lang.Object
org.apache.sis.metadata.sql.IdentifierGenerator
All Implemented Interfaces:
AutoCloseable

final class IdentifierGenerator extends Object implements AutoCloseable
Checks the existence of identifiers (usually primary keys) in a set of tables. This class implements a very naive algorithm and is used only when some reasonably meaningful ID are wanted. If "meaningful" ID is not a requirement, then it is much more efficient to rely on the ID numbers generated automatically by the database.

This class checks if a given identifier exists in the database. If it exists, then it searches for an unused "proposal-n" identifier, where "proposal" is the given identifier and "n" is a number. The algorithm in this class takes advantage of the fact that alphabetical order is not the same than numerical order for scanning a slightly smaller amount of records (however the gain is significant only in special cases. Generally speaking this class is not for tables having thousands of identifier beginning with the given prefix). However, the selected numbers are not guaranteed to be in increasing order if there is "holes" in the sequence of numbers (i.e. if some old records have been deleted). Generating strictly increasing sequence is not a goal of this class, since it would be too costly.

Assumptions

  • SELECT DISTINCT "ID" FROM "Table" WHERE "ID" LIKE 'proposal%' ORDER BY "ID"; is assumed efficient. For example in the case of a PostgreSQL database, it requires PostgreSQL 8.0 or above with a btree index and C locale.
  • The ordering of the '-' and '0' to '9' characters compared to other characters is the same than ASCII. This condition needs to hold only for those particular characters (the ordering between letters does not matter).
Since:
0.8
Version:
0.8
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    private final SQLBuilder
    A helper object for building SQL statements, determined from database metadata.
    private int
    If different than 0, the suggested sequential number to append to the identifier.
    private int
    The greatest sequential number found during the search for a free identifier.
    private int
    Index of the first character to parse in the identifier in order to get its sequential number.
    (package private) static final char
    The character to be used as a separator between the prefix and the sequence number.
    private final PreparedStatement
    The statement to use for searching free identifiers.
  • Constructor Summary

    Constructors
    Constructor
    Description
    IdentifierGenerator(MetadataSource source, String schema, String table, String column, SQLBuilder buffer)
    Creates a new generator.
  • Method Summary

    Modifier and Type
    Method
    Description
    void
    Releases resources used by this IdentifierGenerator.
    (package private) final String
    identifier(String proposal)
    Searches for a free identifier.
    private String
    search(ResultSet rs, String current, String prefix, int expected)
    Searches for an available identifier, assuming that the elements in the given ResultSet are sorted in alphabetical (not numerical) order.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Field Details

    • SEPARATOR

      static final char SEPARATOR
      The character to be used as a separator between the prefix and the sequence number.
      See Also:
    • statement

      private final PreparedStatement statement
      The statement to use for searching free identifiers.
    • buffer

      private final SQLBuilder buffer
      A helper object for building SQL statements, determined from database metadata.
    • parseAt

      private int parseAt
      Index of the first character to parse in the identifier in order to get its sequential number.
    • maximalSequenceNumber

      private int maximalSequenceNumber
      The greatest sequential number found during the search for a free identifier. This will be used only if we found no "hole" in the sequence of numbers.
    • freeSequenceNumber

      private int freeSequenceNumber
      If different than 0, the suggested sequential number to append to the identifier.
  • Constructor Details

    • IdentifierGenerator

      IdentifierGenerator(MetadataSource source, String schema, String table, String column, SQLBuilder buffer) throws SQLException
      Creates a new generator.
      Parameters:
      schema - the schema, or null if none.
      table - the table name where to search for an identifier.
      source - information about the metadata database.
      column - name of the identifier (primary key) column.
      buffer - a helper object for building SQL statements, determined from database metadata.
      Throws:
      SQLException
  • Method Details

    • identifier

      final String identifier(String proposal) throws SQLException
      Searches for a free identifier. If the given proposal is already in use, then this method will search for another identifier of the form "proposal-n" not in use, where "n" is a number.
      Parameters:
      proposal - the proposed identifier. It will be returned if not currently used.
      Returns:
      an identifier which does not exist at the time this method has been invoked.
      Throws:
      SQLException - if an error occurred while searching for an identifier.
    • search

      private String search(ResultSet rs, String current, String prefix, int expected) throws SQLException
      Searches for an available identifier, assuming that the elements in the given ResultSet are sorted in alphabetical (not numerical) order.
      Parameters:
      rs - the result set from which to get next records. Its cursor position is the second record to inspect (i.e. a record has already been extracted before the call to this method).
      current - the ID of the record which has been extracted before the call to this method. It must start with prefix while not equals to prefix.
      prefix - the prefix that an ID must have in order to be accepted.
      expected - the next expected number. If this number is not found, then it will be assumed available.
      Returns:
      the ID that stopped the search (which is going to be the first element of the next iteration), or null if we should stop the search.
      Throws:
      SQLException - if an error occurred while querying the database.
    • close

      public void close() throws SQLException
      Releases resources used by this IdentifierGenerator.
      Specified by:
      close in interface AutoCloseable
      Throws:
      SQLException