Skip to content

Commit

Permalink
Update and fix instanced_inf_table
Browse files Browse the repository at this point in the history
  • Loading branch information
Javagedes committed Sep 25, 2023
1 parent 7f13c5b commit bba75b4
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 40 deletions.
77 changes: 51 additions & 26 deletions edk2toollib/database/tables/instanced_inf_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,48 @@ class TEXT,
dsc TEXT,
component TEXT,
FOREIGN KEY(env) REFERENCES environment(env)
)
);
'''

CREATE_INSTANCED_INF_TABLE_INDEX = '''
CREATE INDEX IF NOT EXISTS instanced_inf_index ON instanced_inf (env);
'''

CREATE_INSTANCED_INF_TABLE_JUNCTION = '''
CREATE TABLE IF NOT EXISTS instanced_inf_junction (
env INTEGER,
component TEXT,
instanced_inf1 TEXT,
instanced_inf2 TEXT,
FOREIGN KEY(env) REFERENCES environment(env),
);
'''

CREATE_INSTANCED_INF_TABLE_JUNCTION_INDEX = '''
CREATE INDEX IF NOT EXISTS instanced_inf_junction_index ON instanced_inf_junction (env);
'''

CREATE_INSTANCED_INF_SOURCE_TABLE_JUNCTION = '''
CREATE TABLE IF NOT EXISTS instanced_inf_source_junction (env, component, instanced_inf, source);
'''

CREATE_INSTNACED_INF_SOURCE_TABLE_JUNCTION_INDEX = '''
CREATE INDEX IF NOT EXISTS instanced_inf_source_junction_index ON instanced_inf_source_junction (env);
'''

INSERT_INSTANCED_INF_ROW = '''
INSERT INTO instanced_inf (env, path, class, name, arch, dsc, component)
VALUES (?, ?, ?, ?, ?, ?, ?)
'''

INSERT_JUNCTION_ROW = '''
INSERT INTO junction (env, table1, key1, table2, key2)
VALUES (?, ?, ?, ?, ?)
INSERT_INF_TABLE_JUNCTION_ROW = '''
INSERT INTO instanced_inf_junction (env, component, instanced_inf1, instanced_inf2)
VALUES (?, ?, ?, ?);
'''

INSERT_INF_TABLE_SOURCE_JUNCTION_ROW = '''
INSERT INTO instanced_inf_source_junction (env, component, instanced_inf, source)
VALUES (?, ?, ?, ?);
'''

class InstancedInfTable(TableGenerator):
Expand All @@ -54,6 +85,11 @@ def __init__(self, *args, **kwargs):
def create_tables(self, db_cursor: Cursor) -> None:
"""Create the tables necessary for this parser."""
db_cursor.execute(CREATE_INSTANCED_INF_TABLE)
db_cursor.execute(CREATE_INSTANCED_INF_TABLE_INDEX)
db_cursor.execute(CREATE_INSTANCED_INF_TABLE_JUNCTION)
db_cursor.execute(CREATE_INSTANCED_INF_TABLE_JUNCTION_INDEX)
db_cursor.execute(CREATE_INSTANCED_INF_SOURCE_TABLE_JUNCTION)
db_cursor.execute(CREATE_INSTNACED_INF_SOURCE_TABLE_JUNCTION_INDEX)

def inf(self, inf: str) -> InfP:
"""Returns a parsed INF object.
Expand Down Expand Up @@ -101,35 +137,24 @@ def _insert_db_rows(self, db_cursor, env_id, inf_entries) -> int:
Inserts all inf's into the instanced_inf table and links source files and used libraries via the junction
table.
"""
# Must use "execute" so that db_cursor.lastrowid is updated.
# Insert all instanced INF rows
rows = [
(env_id, e["PATH"], e.get("LIBRARY_CLASS"), e["NAME"], e["ARCH"], e["DSC"], e["COMPONENT"])
for e in inf_entries
]
for row in rows:
db_cursor.execute(INSERT_INSTANCED_INF_ROW, row)
last_inserted_id = db_cursor.lastrowid
db_cursor.executemany(INSERT_INSTANCED_INF_ROW, rows)

# Mapping used for linking libraries together in the junction table so that the value does not need to be
# queried, which reduces performance greatly.
id_mapping = {}
for idx, e in enumerate(inf_entries):
id_mapping[e["PATH"], e["COMPONENT"]] = last_inserted_id - len(inf_entries) + 1 + idx
# Link isnstaced INF sources
rows = []
for e in inf_entries:
rows += [(env_id, e["COMPONENT"], e["PATH"], source) for source in e["SOURCES_USED"]]
db_cursor.executemany(INSERT_INF_TABLE_SOURCE_JUNCTION_ROW, rows)

# Insert rows into the tables
# Link instanced INF libraries
rows = []
for idx, e in enumerate(inf_entries):
inf_id = last_inserted_id - len(inf_entries) + 1 + idx

# Link all source files to this instanced_inf
rows += [(env_id, "instanced_inf", inf_id, "source", source) for source in e["SOURCES_USED"]]

# link other libraries used by this instanced_inf
rows += [
(env_id, "instanced_inf", inf_id, "instanced_inf", id_mapping.get((library, e["COMPONENT"]), None))
for library in e["LIBRARIES_USED"]
]
db_cursor.executemany(INSERT_JUNCTION_ROW, rows)
for e in inf_entries:
rows += [(env_id, e["COMPONENT"], e["PATH"], library) for library in e["LIBRARIES_USED"]]
db_cursor.executemany(INSERT_INF_TABLE_JUNCTION_ROW, rows)

def _build_inf_table(self, dscp: DscP):
"""Create the instanced inf entries, including components and libraries.
Expand Down
40 changes: 26 additions & 14 deletions tests.unit/database/test_instanced_inf_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@
);
"""

GET_USED_LIBRARIES_QUERY2 = """
SELECT ii.path
FROM instanced_inf AS ii
JOIN instanced_inf_junction AS iij
ON ii.path = iij.instanced_inf2
WHERE
iij.component = ?
AND ii.arch = ?
"""

def test_valid_dsc(empty_tree: Tree):
"""Tests that a typical dsc can be correctly parsed."""
edk2path = Edk2Path(str(empty_tree.ws), [])
Expand All @@ -50,7 +60,7 @@ def test_valid_dsc(empty_tree: Tree):

rows = db.connection.cursor().execute("SELECT * FROM instanced_inf").fetchall()
assert len(rows) == 1
assert rows[0][4] == Path(comp1).stem
assert rows[0][3] == Path(comp1).stem

def test_no_active_platform(empty_tree: Tree, caplog):
"""Tests that the dsc table returns immediately when no ACTIVE_PLATFORM is defined."""
Expand Down Expand Up @@ -138,7 +148,7 @@ def test_library_override(empty_tree: Tree):
}
db.parse(env)
db.connection.execute("SELECT * FROM junction").fetchall()
library_list = db.connection.cursor().execute(GET_USED_LIBRARIES_QUERY, ("TestDriver1", "IA32"))
library_list = db.connection.cursor().execute(f"SELECT instanced_inf2 FROM instanced_inf_junction WHERE instanced_inf1 = '{Path(comp1).as_posix()}'").fetchall()

for path, in library_list:
assert path in [Path(lib2).as_posix(), Path(lib3).as_posix()]
Expand Down Expand Up @@ -180,11 +190,11 @@ def test_scoped_libraries1(empty_tree: Tree):
db.parse(env)

for arch in ["IA32", "X64"]:
for component, in db.connection.execute("SELECT name FROM instanced_inf WHERE component IS NULL and arch is ?;", (arch,)):
component_lib = db.connection.execute(GET_USED_LIBRARIES_QUERY, (component, arch)).fetchone()[0]
assert component.replace("Driver", "Lib") in component_lib
for component, in db.connection.execute("SELECT path FROM instanced_inf WHERE component = path and arch is ?;", (arch,)):
component_lib = db.connection.execute(GET_USED_LIBRARIES_QUERY2, (component, arch)).fetchone()[0]
assert Path(component).name.replace("Driver", "Lib") == Path(component_lib).name

results = db.connection.execute('SELECT key2 FROM junction WHERE table1 = "instanced_inf" AND table2 = "source"').fetchall()
results = db.connection.execute('SELECT source FROM instanced_inf_source_junction').fetchall()
assert len(results) == 3
for source, in results:
assert source in ["File1.c", "File2.c", "File3.c"]
Expand Down Expand Up @@ -246,7 +256,7 @@ def test_missing_library(empty_tree: Tree):
"TARGET": "DEBUG",
}
db.parse(env)
key2 = db.connection.execute("SELECT key2 FROM junction").fetchone()[0]
key2 = db.connection.execute("SELECT instanced_inf2 FROM instanced_inf_junction").fetchone()[0]
assert key2 is None # This library class does not have an instance available, so key2 should be None

def test_multiple_library_class(empty_tree: Tree):
Expand Down Expand Up @@ -281,17 +291,19 @@ def test_multiple_library_class(empty_tree: Tree):

db.parse(env)

results = db.connection.execute("SELECT key1, key2 FROM junction").fetchall()
results = db.connection.execute("SELECT component, instanced_inf1, instanced_inf2 FROM instanced_inf_junction").fetchall()

# Verify that TestDriver1 uses TestLib acting as TestCls1
assert results[0] == ('2','1') # idx 2 is TestDriver1, idx1 is TestLib1 acting as TestCsl1
assert ("TestLib", "TestCls1") == db.connection.execute("SELECT name, class FROM instanced_inf where id = 1").fetchone()
assert ("TestDriver1",) == db.connection.execute("SELECT name FROM instanced_inf where id = 2").fetchone()
assert results[0] == (Path(comp1).as_posix(), Path(comp1).as_posix(), Path(lib1).as_posix()) # idx 2 is TestDriver1, idx1 is TestLib1 acting as TestCsl1
assert ("TestLib", "TestCls1") == db.connection.execute(
"SELECT name, class FROM instanced_inf where path = ? AND component = ?",
(Path(lib1).as_posix(), Path(comp1).as_posix())).fetchone()

# Verify that TestDriver2 uses TestLib acting as TestCls2
assert results[1] == ('4', '3') # idx 4 is TestDriver2, idx 3 is TestLib1 acting as TestCls2
assert ("TestLib", "TestCls2") == db.connection.execute("SELECT name, class FROM instanced_inf where id = 3").fetchone()
assert ("TestDriver2",) == db.connection.execute("SELECT name FROM instanced_inf where id = 4").fetchone()
assert results[1] == (Path(comp2).as_posix(), Path(comp2).as_posix(), Path(lib1).as_posix()) # idx 4 is TestDriver2, idx 3 is TestLib1 acting as TestCls2
assert ("TestLib", "TestCls2") == db.connection.execute(
"SELECT name, class FROM instanced_inf where path = ? AND component = ?",
(Path(lib1).as_posix(), Path(comp2).as_posix())).fetchone()

def test_absolute_paths_in_dsc(empty_tree: Tree):
edk2path = Edk2Path(str(empty_tree.ws), [])
Expand Down

0 comments on commit bba75b4

Please sign in to comment.