Class IdentifierGenerator
- All Implemented Interfaces:
AutoCloseable
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 abtree
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
FieldsModifier and TypeFieldDescriptionprivate 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
ConstructorsConstructorDescriptionIdentifierGenerator
(MetadataSource source, String schema, String table, String column, SQLBuilder buffer) Creates a new generator. -
Method Summary
Modifier and TypeMethodDescriptionvoid
close()
Releases resources used by thisIdentifierGenerator
.(package private) final String
identifier
(String proposal) Searches for a free identifier.private String
Searches for an available identifier, assuming that the elements in the givenResultSet
are sorted in alphabetical (not numerical) order.
-
Field Details
-
SEPARATOR
static final char SEPARATORThe character to be used as a separator between the prefix and the sequence number.- See Also:
-
statement
The statement to use for searching free identifiers. -
buffer
A helper object for building SQL statements, determined from database metadata. -
parseAt
private int parseAtIndex of the first character to parse in the identifier in order to get its sequential number. -
maximalSequenceNumber
private int maximalSequenceNumberThe 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 freeSequenceNumberIf 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:
source
- information about the metadata database.schema
- the schema, ornull
if none.table
- the table name where to search for an identifier.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
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 givenResultSet
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 withprefix
while not equals toprefix
.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
Releases resources used by thisIdentifierGenerator
.- Specified by:
close
in interfaceAutoCloseable
- Throws:
SQLException
-