Question

The possibility of this happening seems extremely unlikely to me because of the problems it could cause, but I figured I'd ask the question anyway...

Imagine a transaction where an autoincrement ID is involved and a value is assigned. Prior to COMMIT, the involved code caches a copy of the assigned ID for later reference. Then the transaction is committed.

Assuming no direct client intervention (deletion or altering of the record), is there any database or situation that would ever automatically alter the ID value immediately upon COMMIT, making the cached ID incorrect? Is it always safe to cache the ID mid-transaction?

One hypothetical case where I can imagine this happening is if some RDBMS implementation inexplicably decided it was necessary to have gapless and time-dependent autoincrement values (since I see many examples of people wanting this). In this hypothetical case, I can imagine some magical shuffling of IDs might be done to fill in gaps caused by post-ID-assignment rollbacks in another transaction (or other gap causer). This would invalidate the cached value.

Anyone know of such an implementation, or other cache killer?

Was it helpful?

Solution

The implementation of generated id values usually involves incrementing a counter value in a short atomic operation. This value is then used for by the requesting transaction and even if that transaction would roll back, the reserved value will never be given back to the pool of free values. So in this light I dont think the situation described is very likely. Also, in pl/sql type of programs you really do need the generated value to be right in order to insert other dependent rows to child tables.

As for the people who are wanting time-ordered gapless id values: the sole purpose of autoincrement/surrogate key is to create an artificial identification for a row. It should have nothing to do with determining the order in which rows were created. There are far better ways to do this, for example using a creation timestamp.

OTHER TIPS

PostgreSQL supports DEFERRED triggers which can alter the data on COMMIT.

CREATE TABLE test_autoinc (id BIGSERIAL);

CREATE TABLE test_other (id BIGSERIAL);

CREATE FUNCTION prc_update_autoinc()
RETURNS TRIGGER
AS
$$
BEGIN
        UPDATE  test_autoinc
        SET     id = id + 10;
        RETURN  NEW;
END;
$$
LANGUAGE 'plpgsql';

CREATE CONSTRAINT TRIGGER
        trg_other_ai
AFTER INSERT
ON      test_other
DEFERRABLE
INITIALLY DEFERRED
FOR EACH ROW
EXECUTE PROCEDURE prc_update_autoinc();

BEGIN TRANSACTION;

INSERT
INTO    test_autoinc
DEFAULT VALUES;

INSERT
INTO    test_other
DEFAULT VALUES;

SELECT  *
FROM    test_autoinc;

COMMIT;

SELECT  *
FROM    test_autoinc;

The first SELECT (right before the COMMIT) returns 1, the second one (right after the COMMIT) returns 11.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top