# for Emacs: -*- mode: org; mode: flyspell; fill-column: 79 -*-

# Update of the database when the project scenario changes:
#   - if the location of the LI file changes, and since we use the full path,
#     this will trigger another parsing.
#   - If it doesn't change, it is possible that the location of the source
#     files have changed though, but this would not be detected currently
#     because we do not parse the LI file again (this is only a problem if both
#     source files contain the same code, since otherwise the xref info has
#     changed and LI has changed). In this case, it is possible that all
#     queries will fail because we do not have info for the new location of the
#     file.
#     ??? We could search on basenames in the files table, for instance.

| TABLE    | files         | file            |   | Stores the list of source and LI files                                                   |
|----------+---------------+-----------------+---+------------------------------------------------------------------------------------------|
| id       | AUTOINCREMENT | PK              |   |                                                                                          |
| path     | TEXT          | NOT NULL, INDEX |   | Full normalized absolute path for the file                                               |
| stamp    | timestamp     | NULL            |   | The timestamp the last time the file was read (only set for LI files for efficiency)     |
| language | TEXT          | NOT NULL        |   | The language for this file (so that we can limit queries to specific languages), or "li" |

| TABLE | f2f_kind      |          |   | All kinds of file relationships |
|-------+---------------+----------+---+---------------------------------|
| id    | AUTOINCREMENT | PK       |   |                                 |
| name  | TEXT          | NOT NULL |   |                                 |

# No unique constraint error for (fromFile, toFile, kind), since a given source
# file might for instance have multiple ALI files if it contains multiple Ada
# units.
# 'is_array' is mostly used by the debugger to know whether the user should be
# able to dereference the variable.

| TABLE    | f2f                   |                   |   | Stores relationships between files |
|----------+-----------------------+-------------------+---+------------------------------------|
| fromFile | FK files(links)       | NOT NULL, NOINDEX |   |                                    |
| toFile   | FK files(linked_from) | NOT NULL, NOINDEX |   |                                    |
| kind     | FK f2f_kind()         | NOT NULL, NOINDEX |   | Kind of dependency                 |

| TABLE                    | entity_kinds | entity_kinds      |       | General kinds for entities (their metaclasses) |
|--------------------------+--------------+-------------------+-------+------------------------------------------------|
| id                       | CHARACTER(1) | PK                |       |                                                |
| display                  | TEXT         | NOT NULL, NOINDEX |       | How to display this entity kind                |
| is_subprogram            | BOOLEAN      | NOINDEX           | false |                                                |
| is_container             | BOOLEAN      | NOINDEX           | false |                                                |
| body_is_full_declaration | BOOLEAN      | NOINDEX           | false |                                                |
| is_abstract              | BOOLEAN      | NOINDEX           | false |                                                |
| is_generic               | BOOLEAN      | NOINDEX           | false |                                                |
| is_access                | BOOLEAN      | NOINDEX           | false |                                                |
| is_type                  | BOOLEAN      | NOINDEX           | false |                                                |
| is_printable_in_gdb      | BOOLEAN      | NOINDEX           | false |                                                |
| is_array                 | BOOLEAN      | NOINDEX           | false |                                                |
| has_methods              | BOOLEAN      | NOINDEX           | false |                                                |

# An entity is known by its name and the location of its declaration. An entry
# in this table cannot exist without a corresponding declaration. To make
# queries faster (when loading ALI files), we thus store the declaration
# directly in this table, rather than as a reference. This speeds up the check
# whether an entity already exists in the table, and removes one INSERT when
# we need to create the entity.
#
# ALI files do not provide the closure of the needed entities: for instance,
# an entity A might be an instantiation of a generic entity B. But all the
# ALI file provides is the file and line where B is declared, not its column.
# In addition, B does not necessarily appear in a.ali. So we need a forward
# declaration for B (since we don't know its name, we insert a new unnamed entity
# at the given line and column -1). We'll try to complete it when b.ali is
# parsed eventually.
#
# Indexes: we tried two indexes: idx1 on name,decl_file,decl_line,decl_column,
# and idx2 on decl_file,decl_line,decl_column.
# Testing with two queries Find_Predefined_Entity (ie using name) and
# Find_Entity_From_Decl (ie only loc):
#                  |    predefined          |  form_decl
#  ----------------+------------------------+----------------------
#    idx1 + idx2   | covering idx1 (~1row)  |  idx2 (~2rows)
#    idx1          | covering idx1 (~1row)  |  scan (~238rows)
#    idx2          | idx2 (~2rows)          |  idx2 (~2rows)
#    no index      | scan (~23rows)         |  scan (~238rows)
# So having only idx2 seems a good compromise (single index is faster at creation)

| TABLE           | entities                        | entity                    |       |                                                                  |
|-----------------+---------------------------------+---------------------------+-------+------------------------------------------------------------------|
| id              | AUTOINCREMENT                   | PK                        |       |                                                                  |
| name            | TEXT                            | NOT NULL, NOINDEX, NOCASE |       | Can be empty for forward decls (see above). Must be UTF-8        |
| kind            | FK entity_kinds()               | NOT NULL, NOINDEX         |       | The E_Kind for this entity                                       |
| decl_file       | FK files(references)            | NOT NULL, NOINDEX         |       | Set to -1 for a predefined entity                                |
| decl_line       | INTEGER                         | NOT NULL, NOINDEX         |       | Set to -1 for a predefined entity                                |
| decl_column     | INTEGER                         | NOT NULL, NOINDEX         |       | Set to -1 for a predefined entity                                |
| decl_caller     | FK entities                     | NULL, NOINDEX             |       | Parent entity                                                    |
| mangled_name    | TEXT                            | NULL                      |       | Mangled name of the entity, if applicable                        |
| exported        | BOOLEAN                         | NOT NULL, NOINDEX         | false | Whether the mangled name is an export or an import of the entity |
| obsolete        | BOOLEAN                         | NOT NULL, NOINDEX         | false | Used for various purposes in GNATCOLL.Xref. Internal only        |
| is_global       | BOOLEAN                         | NOT NULL, NOINDEX         | false | Whether this is a global entity (library-level in Ada)           |
| is_static_local | BOOLEAN                         | NOT NULL, NOINDEX         | false | Whether this is a 'static' variable in C/C++                     |
|-----------------+---------------------------------+---------------------------+-------+------------------------------------------------------------------|
| INDEX:          | decl_file,decl_line,decl_column | entity_loc                |       | Needed during parse                                              |

# Store links between entities.
# For instance, pointer to the parent types, pointed type, returned type,
# renames, primitive operations, instantiation_Of, parameters
#   - Called_Entities: not stored here, it is enough to search the
#     References table using the caller information

| TABLE | e2e_kind      |                   |   | Links between entities |
|-------+---------------+-------------------+---+------------------------|
| id    | AUTOINCREMENT | PK                |   |                        |
| name  | TEXT          | NOT NULL, NOINDEX |   |                        |

# entity-to-entity relationships.
# We cannot have a (fromEntity, toEntity, kind) primary key, because in some
# cases the relationships will be duplicated (for instance, the .gli format for
# C files sometimes improperly record columns for entities. Thus a C subprogram
# might appear to have the same parameter multiple times, although in reality
# each parameter is different but just appears to be on the same column):
#    37V31*gnu_dev_makedev{long long unsigned int} 55>1 55>1 55b1 60t1
#    55m1 __major{unsigned int}
#    55m1 __minor{unsigned int} 57r12

| TABLE      | e2e                      |                   |   |                                                                              |
|------------+--------------------------+-------------------+---+------------------------------------------------------------------------------|
| fromEntity | FK entities(links)       | NOT NULL, NOINDEX |   |                                                                              |
| toEntity   | FK entities(linked_from) | NOT NULL, NOINDEX |   |                                                                              |
| kind       | FK e2e_kind()            | NOT NULL, NOINDEX |   | The type of link.                                                            |
| order_by   | INTEGER                  | NOT NULL, NOINDEX | 1 | Ordering among the references. Used for instance for subprogram parameters   |
|------------+--------------------------+-------------------+---+------------------------------------------------------------------------------|
| INDEX:     | "fromEntity"             | e2e_from          |   | Not needed during parsing                                                    |
| INDEX:     | "toEntity"               | e2e_to            |   | Not needed during parsing                                                    |

| TABLE             | reference_kinds | reference_kind   |       | Kind of references                                      |
|-------------------+-----------------+------------------+-------+---------------------------------------------------------|
| id                | CHARACTER(1)    | PK               |       | The character found in the ALI file                     |
| display           | TEXT            | NOT NULL,NOINDEX |       | Label to display the reference                          |
| is_real           | BOOLEAN         | NOINDEX          | true  | Whether the name of the entity appears at that location |
| is_read           | BOOLEAN         | NOINDEX          | false |                                                         |
| is_write          | BOOLEAN         | NOINDEX          | false |                                                         |
| is_end            | BOOLEAN         | NOINDEX          | false | Whether this marks the end of a scope (spec or body)    |
| show_in_callgraph | BOOLEAN         | NOINDEX          | true  | Whether this ref. should be shown in the call graph     |
| is_dispatching    | BOOLEAN         | NOINDEX          | false | Whether this is a dispatching call                      |
| is_implicit       | BOOLEAN         | NOINDEX          | false |                                                         |

# We store instantiations as a string for now: currently, they are only used to
# display tooltips in GPS as to where an entity comes from. This can easily be
# parsed from the string. But the string also makes it easy to find all
# references from the same instance as the one the user clicked on, which would
# be harder (and slower) to do if we stored the instances in a separate table,
# where each instance potentially points to its parent.
# The format is "file1|line1 file2|line2 ..." where file1|line1 is itself
# instantiated at file2|line2.
#
# This table might contain duplicates (for instance from .gli files). It is
# also possible that a given location is duplicated with different kinds, for
# instance the argument for an "in out" parameter has both a "read" and
# "modified" entries.
#
# Indexes: we have an index on "file". We used to have one on
# "file,line,column" instead. In practice, "explain query plan" shows that both
# have roughly the same performance on the DELETE query used to cleanup
# references when updating an ALI file, and on the SELECT query to find which
# entity occurs at a given location. However, the database is slightly smaller,
# and the generation of the index slightly faster, when only storing the file
# in the index.

| TABLE              | entity_refs             | entity_ref         |   |                                                     |
|--------------------+-------------------------+--------------------+---+-----------------------------------------------------|
| entity             | FK entities(references) | NOT NULL, NOINDEX  |   | The entity to which we have a reference             |
| file               | FK files(references)    | NOT NULL, NOINDEX  |   |                                                     |
| line               | INTEGER                 | NOT NULL, NOINDEX  |   |                                                     |
| column             | INTEGER                 | NOT NULL, NOINDEX  |   |                                                     |
| kind               | FK reference_kinds()    | NOT NULL, NOINDEX  |   | Type of reference (same letter as in ALI files)     |
| caller             | FK entities(calling)    | NULL, NOINDEX      |   | Enclosing entity at that location                   |
| from_instantiation | TEXT                    | NOINDEX            |   | Instances in which the ref occurs                   |
|--------------------+-------------------------+--------------------+---+-----------------------------------------------------|
| INDEX:             | "file"                  | entity_refs_file   |   | Needed during parsing to cleanup outdated ALI files |
| INDEX:             | "entity"                | entity_refs_entity |   | Not needed during parsing                           |
