Repository navigation
Description
After #10348 (merge ea180479d7), three schema sequences that worked on main before it (d21784c4d8) and on 26.10.2 now end in a refused statement that still changes the schema. All three rename an indexed supertype (#10348 changed how a rename relabels the sub-indexes of an inherited index); the refusal names the type's old name, or the index as not valid. In case 3 the schema in memory and the schema after a reopen also differ: the refused DROP TYPE removed T64 in memory, T64 comes back after the reopen, and the index T66[p] is gone. Found by the schema fuzz I ran to verify #10348 (SchemaOps.java, seeds 1-30), shrunk to these statements.
1. DROP TYPE of a subtype after its indexed supertype was renamed.
CREATE DOCUMENT TYPE T22 BUCKETS 3
CREATE DOCUMENT TYPE T25 EXTENDS T22
CREATE PROPERTY T22.p STRING
CREATE INDEX ON T22 (p) NOTUNIQUE
ALTER TYPE T22 NAME T28
DROP TYPE T25- on the merge:
REFUSED SchemaException: Cannot drop the index 'T25_0_N' (error=com.arcadedb.exception.SchemaException: Type with name 'T22' was not found), and yet the schema changed. Afterwards:T25{super [], buckets [], indexes []} T28{super [], buckets [T28_0, T28_1, T28_2], indexes [T28[p]]}; after a reopen:T25{super [], buckets [], indexes []} T28{super [], buckets [T28_0, T28_1, T28_2], indexes [T28[p]]} - on
d21784c4d8and on 26.10.2: the statement succeeds; after a reopen:T28{super [], buckets [T28_0, T28_1, T28_2], indexes [T28[p]]}
2. ALTER TYPE ... BUCKET - on a renamed subtype after its indexed supertype was renamed.
CREATE EDGE TYPE T1
CREATE EDGE TYPE T2 EXTENDS T1
ALTER TYPE T2 NAME T4
CREATE PROPERTY T1.p STRING
CREATE INDEX ON T1 (p) NOTUNIQUE
ALTER TYPE T1 NAME T10
ALTER TYPE T4 BUCKET -T4_0- on the merge:
REFUSED SchemaException: Cannot drop the index 'T4_0_N' (error=com.arcadedb.exception.SchemaException: Type with name 'T1' was not found), and yet the schema changed. Afterwards:T10{super [], buckets [T10_0], indexes [T10[p]]} T4{super [T10], buckets [], indexes []}; after a reopen:T10{super [], buckets [T10_0], indexes [T10[p]]} T4{super [T10], buckets [], indexes []} - on
d21784c4d8and on 26.10.2: the statement succeeds; after a reopen:T10{super [], buckets [T10_0], indexes [T10[p]]} T4{super [T10], buckets [], indexes []}
3. An indexed type renamed twice loses its last bucket, then DROP TYPE of its subtype.
CREATE DOCUMENT TYPE T1
ALTER TYPE T1 NAME T13
CREATE DOCUMENT TYPE T15 EXTENDS T13
CREATE PROPERTY T15.p STRING
CREATE INDEX ON T15 (p) NOTUNIQUE
CREATE DOCUMENT TYPE T64 EXTENDS T15 BUCKETS 4
ALTER TYPE T15 NAME T65
ALTER TYPE T65 NAME T66
ALTER TYPE T66 BUCKET -T66_0
DROP TYPE T64- on the merge:
REFUSED IndexException: Index 'T66[p]' is not valid. Probably has been drop or rebuilt, and yet the schema changed. Afterwards:T13{super [], buckets [T13_0], indexes []} T66{super [T13], buckets [], indexes [T66[p]]}; after a reopen:T13{super [], buckets [T13_0], indexes []} T64{super [T66], buckets [], indexes []} T66{super [T13], buckets [], indexes []} - on
d21784c4d8and on 26.10.2: the statement succeeds; after a reopen:T13{super [], buckets [T13_0], indexes []} T66{super [T13], buckets [], indexes []}
Embedded, eclipse-temurin 25 (-XX:+UseCompactObjectHeaders) and 21, identical on both; CI-built jars of each commit; each case on a fresh database. Generated index names are shortened to _N.
RenameIndex.java
// REMOVE WHEN: the rename-and-index schema findings on ea180479d7 (#10348's merge, 2026-10-20) are filed and verified on their fix.
// java RenameIndex.java DBDIR: three cases, each on a fresh database. Every statement's outcome, then the schema (types, supertypes,
// buckets, indexes), then a close (which writes the schema) and the schema after a reopen.
import com.arcadedb.database.*;
import com.arcadedb.schema.*;
import java.util.*;
public class RenameIndex {
static final String[][] CASES = {
{ "1: DROP TYPE of a subtype after its indexed supertype was renamed",
"CREATE DOCUMENT TYPE T22 BUCKETS 3", "CREATE DOCUMENT TYPE T25 EXTENDS T22", "CREATE PROPERTY T22.p STRING", "CREATE INDEX ON T22 (p) NOTUNIQUE",
"ALTER TYPE T22 NAME T28", "DROP TYPE T25" },
{ "2: ALTER TYPE ... BUCKET - on a renamed subtype after its indexed supertype was renamed",
"CREATE EDGE TYPE T1", "CREATE EDGE TYPE T2 EXTENDS T1", "ALTER TYPE T2 NAME T4", "CREATE PROPERTY T1.p STRING", "CREATE INDEX ON T1 (p) NOTUNIQUE",
"ALTER TYPE T1 NAME T10", "ALTER TYPE T4 BUCKET -T4_0" },
{ "3: an indexed type renamed twice loses its last bucket, then DROP TYPE of its subtype",
"CREATE DOCUMENT TYPE T1", "ALTER TYPE T1 NAME T13", "CREATE DOCUMENT TYPE T15 EXTENDS T13", "CREATE PROPERTY T15.p STRING", "CREATE INDEX ON T15 (p) NOTUNIQUE",
"CREATE DOCUMENT TYPE T64 EXTENDS T15 BUCKETS 4", "ALTER TYPE T15 NAME T65", "ALTER TYPE T65 NAME T66", "ALTER TYPE T66 BUCKET -T66_0", "DROP TYPE T64" } };
public static void main(String[] a) throws Exception {
System.out.println("RESULT engine " + com.arcadedb.Constants.getRawVersion() + " " + com.arcadedb.Constants.getBuildNumber());
int c = 0;
for (String[] cs : CASES) {
System.out.println("RESULT === case " + cs[0]);
DatabaseFactory f = new DatabaseFactory(a[0] + "/c" + (c++)); if (f.exists()) f.open().drop(); Database db = f.create();
for (int i = 1; i < cs.length; i++) {
String before = schema(db), r;
try { db.command("sql", cs[i]).close(); r = "ok"; } catch (Exception e) { r = "REFUSED " + e.getClass().getSimpleName() + ": " + e.getMessage(); }
String after = schema(db);
System.out.println("RESULT " + cs[i] + " -> " + r + (r.startsWith("REFUSED") && !before.equals(after) ? " | SCHEMA CHANGED ANYWAY" : ""));
}
System.out.println("RESULT schema: " + schema(db));
try { db.close(); System.out.println("RESULT close: ok"); } catch (Exception e) { System.out.println("RESULT close: " + e.getClass().getSimpleName() + ": " + e.getMessage()); }
try { Database d2 = f.open(); System.out.println("RESULT after reopen: " + schema(d2)); d2.close(); }
catch (Exception e) { System.out.println("RESULT reopen: " + e.getClass().getSimpleName() + ": " + e.getMessage()); }
}
System.exit(0);
}
static String schema(Database db) {
StringBuilder b = new StringBuilder(); List<DocumentType> ts = new ArrayList<>(db.getSchema().getTypes()); ts.sort(Comparator.comparing(DocumentType::getName));
for (DocumentType t : ts) {
List<String> sup = new ArrayList<>(); for (DocumentType s : t.getSuperTypes()) sup.add(s.getName());
List<String> bk = new ArrayList<>(); for (var x : t.getBuckets(false)) bk.add(x.getName());
List<String> ix = new ArrayList<>(); try { for (var x : t.getAllIndexes(false)) ix.add(x.getName()); } catch (Exception e) { ix.add("EXC " + e.getMessage()); }
b.append(t.getName()).append("{super ").append(sup).append(", buckets ").append(bk).append(", indexes ").append(ix).append("} ");
}
return b.toString().trim();
}
}
Activity
fix(#10420, #10412, #10267): a sub-index names the type owning its bu…
lvca commentedon Oct 20, 2026
Fixed in #10422, released in 26.11.1.
Cause: an index created with
CREATE INDEXon a type that already had sub types kept the index of each sub type's bucket labelled with the super type until the next reopen. After renaming the super type,DROP TYPEandALTER TYPE ... BUCKET -on the sub type could not find it. Dropping the last sub type of an indexed type that had lost its own buckets could also leave an empty index behind.Now the index of each bucket names the type that owns the bucket as soon as it is created, so your three sequences complete and the schema is the same before and after a reopen.
A refused schema statement that still keeps part of its changes is a separate problem, tracked in #10421.
❤️ Thanks for helping make ArcadeDB better! ArcadeDB is free and open source, sustained by its community. If it's useful to you or your company, please consider becoming a sponsor to keep development going.
fix(#10420, #10412, #10267): a sub-index names the type owning its bu…