Visitar URL original
A refused schema statement still changes the schema: CREATE TYPE with a taken bucket leaves the type behind, and DROP TYPE after a subtype rename unlinks the subtype and loses the index · Issue #10317 · ArcadeData/arcadedb · GitHub
Skip to content

A refused schema statement still changes the schema: CREATE TYPE with a taken bucket leaves the type behind, and DROP TYPE after a subtype rename unlinks the subtype and loses the index #10317

Closed

Description

@tae898

Embedded, on main 14ce29fb67 and on 26.10.2 (e5040d0339), eclipse-temurin 25 and 21 (the four print the same): two schema statements are refused with an exception and still change the schema. A caller that catches the exception and carries on has a schema that is neither the old one nor the new one, and in the second case an index is lost after a reopen.

A. CREATE DOCUMENT TYPE B BUCKET A_0, where A_0 belongs to type A, is refused, but B is created anyway (with no bucket) and is still there after a reopen. After each statement the schema is printed as every type with its supertypes, buckets and indexes:

CREATE DOCUMENT TYPE A -> ok
  schema: A{super [], buckets [A_0], indexes []}
CREATE DOCUMENT TYPE B BUCKET A_0 -> REFUSED SchemaException: Cannot add the bucket 'A_0' to the type 'B', because the bucket is already associated to the type 'A' | SCHEMA CHANGED ANYWAY
  schema: A{super [], buckets [A_0], indexes []} B{super [], buckets [], indexes []}
  after reopen: A{super [], buckets [A_0], indexes []} B{super [], buckets [], indexes []}

B. DROP TYPE T5 of an indexed supertype whose subtype was renamed is refused, and the refusal unlinks the subtype from T5 in memory; after a reopen the subtype is linked again but the index T5[p] is gone. Inside a transaction the same statement is refused with Cannot drop the index 'T5[p]' (... Cannot drop the index 'T10_0_<n>' (... Type with name 'T10' was not found)): the per-bucket index of the subtype still carries the subtype's old name after ALTER TYPE T10 NAME T11.

CREATE DOCUMENT TYPE T5 -> ok
  schema: T5{super [], buckets [T5_0], indexes []}
CREATE PROPERTY T5.p STRING -> ok
  schema: T5{super [], buckets [T5_0], indexes []}
CREATE INDEX ON T5 (p) NOTUNIQUE -> ok
  schema: T5{super [], buckets [T5_0], indexes [T5[p]]}
CREATE DOCUMENT TYPE T10 EXTENDS T5 -> ok
  schema: T10{super [T5], buckets [T10_0], indexes []} T5{super [], buckets [T5_0], indexes [T5[p]]}
ALTER TYPE T10 NAME T11 -> ok
  schema: T11{super [T5], buckets [T11_0], indexes []} T5{super [], buckets [T5_0], indexes [T5[p]]}
DROP TYPE T5 -> REFUSED IndexException: Index 'T5[p]' is not valid. Probably has been drop or rebuilt | SCHEMA CHANGED ANYWAY
  schema: T11{super [], buckets [T11_0], indexes []} T5{super [], buckets [T5_0], indexes [T5[p]]}
  after reopen: T11{super [T5], buckets [T11_0], indexes []} T5{super [], buckets [T5_0], indexes []}

C. The same statements without the rename (control): DROP TYPE T5 succeeds, T10 loses its supertype and the index goes with T5, as expected.

CREATE DOCUMENT TYPE T5 -> ok
  schema: T5{super [], buckets [T5_0], indexes []}
CREATE PROPERTY T5.p STRING -> ok
  schema: T5{super [], buckets [T5_0], indexes []}
CREATE INDEX ON T5 (p) NOTUNIQUE -> ok
  schema: T5{super [], buckets [T5_0], indexes [T5[p]]}
CREATE DOCUMENT TYPE T10 EXTENDS T5 -> ok
  schema: T10{super [T5], buckets [T10_0], indexes []} T5{super [], buckets [T5_0], indexes [T5[p]]}
DROP TYPE T5 -> ok
  schema: T10{super [], buckets [T10_0], indexes []}
  after reopen: T10{super [], buckets [T10_0], indexes []}

Expected: a refused statement leaves the schema as it was (A: no type B; B: T11 still extends T5, and T5[p] survives the reopen), and in B, ALTER TYPE ... NAME renames the per-bucket indexes it inherits, so that the drop in B behaves like the one in C.

Found by a randomized schema-operation probe held against a model of the expected schema; both cases also show on 26.10.2, so they are not from the recent schema changes in #10259 (that probe found nothing new there).

SchemaRefusal.java: java -cp 'lib/*' SchemaRefusal.java <dir>
// Two schema statements that are refused but still change the schema. After every statement: its outcome, then every
// type with its supertypes, its buckets and its indexes; at the end the same after close and reopen.
//   java SchemaRefusal.java <dir>
import com.arcadedb.database.*;
import com.arcadedb.index.*;
import com.arcadedb.schema.*;
import java.util.*;

public class SchemaRefusal {
  static Database db;

  public static void main(String[] a) throws Exception {
    run(a[0] + "/bucket", "A: CREATE TYPE with a bucket another type owns",
        "CREATE DOCUMENT TYPE A", "CREATE DOCUMENT TYPE B BUCKET A_0");
    run(a[0] + "/drop", "B: DROP TYPE of an indexed supertype whose subtype was renamed",
        "CREATE DOCUMENT TYPE T5", "CREATE PROPERTY T5.p STRING", "CREATE INDEX ON T5 (p) NOTUNIQUE",
        "CREATE DOCUMENT TYPE T10 EXTENDS T5", "ALTER TYPE T10 NAME T11", "DROP TYPE T5");
    run(a[0] + "/drop-norename", "C: the same DROP TYPE without the rename (control)",
        "CREATE DOCUMENT TYPE T5", "CREATE PROPERTY T5.p STRING", "CREATE INDEX ON T5 (p) NOTUNIQUE",
        "CREATE DOCUMENT TYPE T10 EXTENDS T5", "DROP TYPE T5");
  }

  static void run(String path, String label, String... stmts) {
    DatabaseFactory f = new DatabaseFactory(path); if (f.exists()) f.open().drop(); db = f.create();
    System.out.println("RESULT === " + label);
    for (String s : stmts) {
      String before = state();
      String out;
      try {
        if (s.startsWith("SELECT")) { try (var rs = db.query("sql", s)) { Object c = rs.next().getProperty("count(*)"); out = "ok, count " + c; } }
        else { db.command("sql", s).close(); out = "ok"; }
      }
      catch (Exception e) { out = "REFUSED " + e.getClass().getSimpleName() + ": " + String.valueOf(e.getMessage()).replaceAll("\\s+", " "); }
      String after = state();
      System.out.println("RESULT " + s + " -> " + out + (out.startsWith("REFUSED") && !before.equals(after) ? " | SCHEMA CHANGED ANYWAY" : ""));
      System.out.println("RESULT   schema: " + after);
    }
    db.close(); db = f.open();
    System.out.println("RESULT   after reopen: " + state());
    db.close();
  }

  static String state() {
    List<String> out = new ArrayList<>();
    List<DocumentType> types = new ArrayList<>(db.getSchema().getTypes()); types.sort(Comparator.comparing(DocumentType::getName));
    for (DocumentType t : types) {
      List<String> sup = new ArrayList<>(); for (DocumentType s : t.getSuperTypes()) sup.add(s.getName());
      List<String> bk = new ArrayList<>(); for (var b : t.getBuckets(false)) bk.add(b.getName());
      List<String> ix = new ArrayList<>(); for (var i : t.getAllIndexes(false)) ix.add(i.getName());
      out.add(t.getName() + "{super " + sup + ", buckets " + bk + ", indexes " + ix + "}");
    }
    return String.join(" ", out);
  }
}

Activity

  1. added
    engineCore engine: document/schema API
    severity:minorCosmetic, documentation, edge case, or a workaround exists
    on Oct 18, 2026
  2. added this to the 26.11.1 milestone on Oct 18, 2026
  3. self-assigned this
    on Oct 19, 2026
  4. added theissue type on Oct 19, 2026
  5. added 2 commits that reference this issue on Oct 19, 2026
  6. lvca commented on Oct 19, 2026

    @lvca
    Member

    Fixed in #10348, thanks @ItsDeadlyProgrammer.

    • CREATE TYPE B BUCKET A_0, where the bucket belongs to another type, is now refused before anything is created, so no empty B is left behind. The same holds when a bucket is listed twice, and when IF NOT EXISTS ... BUCKETS n grows an existing type onto a bucket another type owns (the existing type stays as it was).
    • The DROP TYPE refusal that lost the index was caused by ALTER TYPE ... NAME on a sub type: the sub-index of an inherited index kept the old type name. Renaming a sub type now renames those sub-indexes too (and renaming a super type no longer relabels its sub types' sub-indexes), so the DROP TYPE in the report works.

    The fixes will be available in the next release. Docs updated: the CREATE TYPE and ALTER TYPE ... NAME sections of the SQL reference.


    ❤️ 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.

  7. added a commit that references this issue on Oct 20, 2026
  8. added 2 commits that reference this issue on Nov 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugengineCore engine: document/schema APIseverity:minorCosmetic, documentation, edge case, or a workaround existssql

Type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions