You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Expression index on a computed column is not usable in other attachments and gets corrupted ("missing entries") when the table has a computed column calling a procedure that reads the same table #9165
This report was created with the support of AI. I hope it will help with the analysis of the root cause of the problem.
Related to #7945 — same root symptom, but it is not only a plan/optimizer problem: the index gets physically corrupted.
Environment
Firebird 5.0.4.1812, Linux x64, SuperServer, Forced Writes ON, default firebird.conf
a computed column C_PROC that calls a stored procedure, and that procedure reads table T itself,
a computed column C_KEY that depends on another computed column C_BIT,
an expression index on C_KEY.
Observed behaviour:
Only the attachment that created (or rebuilt) the index can use it. In any new attachment the optimizer does not match the index (PLAN (T NATURAL)), and forcing it fails with index T_C_KEY cannot be used in the specified plan (this is Problem with using a computed index on a computed column #7945).
When a new attachment updates a row so that the value of C_KEY changes, and the old record version is then garbage collected, the index loses all entries for that row. gfix -v -full reports:
Error: Index 2 is corrupt {missing entries for record 0} in table T (128)
ALTER INDEX ... INACTIVE / ACTIVE fixes it, but the corruption returns as soon as rows are modified again from normal attachments.
CREATE DATABASE 'localhost:/tmp/repro.fdb';
SET TERM ^ ;
CREATE PROCEDURE P_READ_T (ID INTEGER) RETURNS (RES INTEGER) ASBEGIN SUSPEND; END^
SET TERM ; ^
CREATETABLET (
ID INTEGERNOT NULLPRIMARY KEY,
FLAGS INTEGER DEFAULT 0NOT NULL,
C_PROC COMPUTED BY ((SELECT RES FROM P_READ_T(T.ID))),
C_BIT COMPUTED BY (CAST(SIGN(BIN_AND(FLAGS, 64)) ASSMALLINT)),
C_KEY COMPUTED BY (CASE WHEN (C_BIT =1) THEN ID ELSE -ID END)
);
SET TERM ^ ;
ALTER PROCEDURE P_READ_T (ID INTEGER) RETURNS (RES INTEGER) ASBEGINSELECTT.FLAGSFROM T WHERET.ID= :ID INTO :RES;
SUSPEND;
END^
EXECUTE BLOCK AS
DECLARE I INTEGER=1;
BEGIN
WHILE (I <=1000) DO
BEGININSERT INTO T (ID, FLAGS) VALUES (:I, 0);
I = I +1;
END
END^
SET TERM ; ^
COMMIT;
CREATEINDEXT_C_KEYON T COMPUTED BY (C_KEY);
COMMIT;
SET PLAN ON;
-- Attachment that created the index: index is usedSELECTCOUNT(*) FROM T WHERE C_KEY >0;
-- New attachment
CONNECT 'localhost:/tmp/repro.fdb';
SET PLAN ON;
-- Expected: PLAN (T INDEX (T_C_KEY)); actual: PLAN (T NATURAL)SELECTCOUNT(*) FROM T WHERE C_KEY >0;
UPDATE T SET FLAGS = BIN_OR(FLAGS, 64) WHERE ID <=10;
COMMIT;
-- Garbage collection of the old record versionsSELECTCOUNT(*) FROM T;
COMMIT;
EXIT;
Actual result
PLAN (T INDEX (T_C_KEY)) <- attachment that created the index
PLAN (T NATURAL) <- new attachment
gfix -v -full:
Summary of validation errors
Number of index page errors : 1
firebird.log:
Error: Index 2 is corrupt {missing entries for record 0} in table T (128)
Expected result
The index is usable in every attachment.
Validation reports no errors.
Additional observations
All results below were checked with gfix -v -full. Each combination was run with the first statement in the new attachment being either the UPDATE or a SELECT ... WHERE C_KEY < 0, and with garbage collection done either by the same attachment or by gfix -sweep. All variants gave the same result.
Change made in a new attachment
P_READ_T reads T
P_READ_T does not read T (RES = :ID;)
bit 64: 0 → 1 (C_KEY changes)
corrupted
OK
bit 64: 1 → 0 (C_KEY changes)
corrupted
OK
other bits only (C_KEY unchanged)
OK
OK
The problem does not depend on the procedure reading computed columns. Reading only ordinary columns of T is enough.
Every row whose C_KEY changes in a normal attachment loses its index entries (100 of 100 in one test). Validation reports only the first one.
Online validation (fbsvcmgr ... action_validate) did not report the corruption in some runs where gfix -v -full did.
The real-world case is an ERP table with about 20 computed columns calling selectable procedures that read the same table. There, a flag bit is set or cleared by ordinary UPDATEs from the application, and the index has to be rebuilt periodically.
This report was created with the support of AI. I hope it will help with the analysis of the root cause of the problem.
Related to #7945 — same root symptom, but it is not only a plan/optimizer problem: the index gets physically corrupted.
Environment
firebird.confDescription
Table
Thas:C_PROCthat calls a stored procedure, and that procedure reads tableTitself,C_KEYthat depends on another computed columnC_BIT,C_KEY.Observed behaviour:
PLAN (T NATURAL)), and forcing it fails withindex T_C_KEY cannot be used in the specified plan(this is Problem with using a computed index on a computed column #7945).C_KEYchanges, and the old record version is then garbage collected, the index loses all entries for that row.gfix -v -fullreports:ALTER INDEX ... INACTIVE/ACTIVEfixes it, but the corruption returns as soon as rows are modified again from normal attachments.Steps to reproduce
Adjust the database path (2 places) and run:
repro.sql:Actual result
gfix -v -full:firebird.log:
Expected result
Additional observations
All results below were checked with
gfix -v -full. Each combination was run with the first statement in the new attachment being either theUPDATEor aSELECT ... WHERE C_KEY < 0, and with garbage collection done either by the same attachment or bygfix -sweep. All variants gave the same result.P_READ_TreadsTP_READ_Tdoes not readT(RES = :ID;)C_KEYchanges)C_KEYchanges)C_KEYunchanged)Tis enough.C_KEYchanges in a normal attachment loses its index entries (100 of 100 in one test). Validation reports only the first one.fbsvcmgr ... action_validate) did not report the corruption in some runs wheregfix -v -fulldid.UPDATEs from the application, and the index has to be rebuilt periodically.