aboutsummaryrefslogtreecommitdiff
path: root/source/20-codegen-compiler/CodegenModel.cpp
diff options
context:
space:
mode:
authorrtk0c <[email protected]>2022-06-24 17:34:56 -0700
committerrtk0c <[email protected]>2022-06-24 17:34:56 -0700
commitfd66e74445f50426aa8a137b0a9cfa6d088b953c (patch)
tree6e5d2557f567a7e11a7cc83612af482f27481a3a /source/20-codegen-compiler/CodegenModel.cpp
parent4386c02d61b37c0d5c508895df2f028b8ea2057c (diff)
Changeset: 75 Add feature to delete entries from the database that belong to currently processed files
Diffstat (limited to 'source/20-codegen-compiler/CodegenModel.cpp')
-rw-r--r--source/20-codegen-compiler/CodegenModel.cpp106
1 files changed, 77 insertions, 29 deletions
diff --git a/source/20-codegen-compiler/CodegenModel.cpp b/source/20-codegen-compiler/CodegenModel.cpp
index 08323bc..4a9a8f8 100644
--- a/source/20-codegen-compiler/CodegenModel.cpp
+++ b/source/20-codegen-compiler/CodegenModel.cpp
@@ -31,7 +31,7 @@ public:
// A number for `PRAGMA user_vesrion`, representing the current database version. Increment when the table format changes.
#define CURRENT_DATABASE_VERSION 1
-constexpr int64_t kGlobalNamespaceRowId = 1;
+constexpr int64_t kGlobalNamespaceId = 1;
struct SQLiteDatabase {
sqlite3* database = nullptr;
@@ -49,6 +49,11 @@ struct SQLiteDatabase {
struct SQLiteStatement {
sqlite3_stmt* stmt = nullptr;
+ SQLiteStatement(const SQLiteStatement&) = delete;
+ SQLiteStatement& operator=(const SQLiteStatement&) = delete;
+
+ SQLiteStatement() = default;
+
~SQLiteStatement() {
// NOTE: calling with NULL is a harmless no-op
// NOTE: we don't care about the error code, because they are returned if the statement has errored in the most recent execution
@@ -97,6 +102,8 @@ public:
SQLiteStatement findOrStoreNamespaceStmt;
SQLiteStatement storeEnumStmt;
SQLiteStatement storeEnumElmStmt;
+ SQLiteStatement deleteStructDeclByFilenameStmt;
+ SQLiteStatement deleteEnumDeclByFilenameStmt;
void InitializeCoreStatements() {
char* errMsg = nullptr;
@@ -108,34 +115,45 @@ public:
result = sqlite3_exec(database, R"""(
BEGIN TRANSACTION;
CREATE TABLE Namespaces(
- ParentNamespaceRowId INTEGER REFERENCES Namespaces(rowid),
+ -- NOTE: SQLite forbids foreign keys referencing the implicit `rowid` column, we have to create an alias for it
+ Id INTEGER PRIMARY KEY,
+ ParentNamespaceId INTEGER REFERENCES Namespaces(Id),
Name TEXT,
- UNIQUE (ParentNamespaceRowId, Name)
+ UNIQUE (ParentNamespaceId, Name)
);
CREATE TABLE DeclStructs(
- NamespaceRowId INTEGER REFERENCES Namespaces(rowid),
- ParentStructRowId INTEGER REFERENCES DeclStructs(rowid),
+ Id INTEGER PRIMARY KEY,
+ NamespaceId INTEGER REFERENCES Namespaces(Id),
+ ParentStructId INTEGER REFERENCES DeclStructs(Id),
Name TEXT,
- UNIQUE (NamespaceRowId, Name)
+ FileName TEXT,
+ UNIQUE (NamespaceId, Name)
);
CREATE TABLE DeclEnums(
- NamespaceRowId INTEGER REFERENCES Namespaces(rowid),
+ Id INTEGER PRIMARY KEY,
+ NamespaceId INTEGER REFERENCES Namespaces(Id),
Name TEXT,
UnderlyingType TEXT,
- UNIQUE (NamespaceRowId, Name)
+ FileName TEXT,
+ UNIQUE (NamespaceId, Name)
);
CREATE TABLE DeclEnumElements(
- EnumRowId INTEGER REFERENCES DeclEnums(rowid),
+ EnumId INTEGER REFERENCES DeclEnums(Id) ON DELETE CASCADE,
Name TEXT,
Value INTEGER,
- UNIQUE (EnumRowId, Name)
+ UNIQUE (EnumId, Name)
);
-INSERT INTO Namespaces(rowid, ParentNamespaceRowId, Name)
+CREATE INDEX Index_DeclStructs_FileName
+ ON DeclStructs(FileName);
+CREATE INDEX Index_DeclEnums_FileName
+ ON DeclEnums(FileName);
+
+INSERT INTO Namespaces(Id, ParentNamespaceId, Name)
VALUES
- -- Special global namespace that has no parent, and rowid should always be 1
+ -- Special global namespace that has no parent, and Id should always be 1
(1, NULL, "<global namespace>");
COMMIT TRANSACTION;
@@ -168,7 +186,7 @@ COMMIT TRANSACTION;
/// \return Row ID of the namespace, or 0 if it currently doesn't exist.
int64_t FindNamespace(const DeclNamespace* ns) {
if (!ns) {
- return kGlobalNamespaceRowId;
+ return kGlobalNamespaceId;
}
InitializeStmt_findNamespaceStmt();
@@ -178,7 +196,7 @@ COMMIT TRANSACTION;
/// \return Row ID of the namespace.
int64_t FindOrStoreNamespace(const DeclNamespace* ns) {
if (!ns) {
- return kGlobalNamespaceRowId;
+ return kGlobalNamespaceId;
}
InitializeStmt_findNamespaceStmt();
@@ -189,15 +207,15 @@ COMMIT TRANSACTION;
private:
void InitializeStmt_findNamespaceStmt() {
findNamespaceStmt.InitializeLazily(database, R"""(
-SELECT rowid FROM Namespaces WHERE ParentNamespaceRowId = ?1 AND Name = ?2;
+SELECT Id FROM Namespaces WHERE ParentNamespaceId = ?1 AND Name = ?2;
)"""sv);
}
void InitializeStmt_findOrStoreNamespaceStmt() {
findOrStoreNamespaceStmt.InitializeLazily(database, R"""(
-INSERT INTO Namespaces(ParentNamespaceRowId, Name)
+INSERT INTO Namespaces(ParentNamespaceId, Name)
VALUES (?1, ?2)
- RETURNING rowid;
+ RETURNING Id;
)"""sv);
}
@@ -210,7 +228,7 @@ INSERT INTO Namespaces(ParentNamespaceRowId, Name)
return 0;
}
} else {
- parentNsRowId = kGlobalNamespaceRowId;
+ parentNsRowId = kGlobalNamespaceId;
}
return FindNamespaceImpl(ns, parentNsRowId);
@@ -239,7 +257,7 @@ INSERT INTO Namespaces(ParentNamespaceRowId, Name)
sqlite3_stmt* stmt = findOrStoreNamespaceStmt;
int64_t parentRowId = ns.container
? FindOrStoreNamespaceImpl(*ns.container)
- : kGlobalNamespaceRowId;
+ : kGlobalNamespaceId;
sqlite3_bind_int64(stmt, 1, parentRowId);
sqlite3_bind_text(stmt, 2, ns.name.c_str(), ns.name.size(), nullptr);
int result = sqlite3_step(stmt);
@@ -367,8 +385,10 @@ CodegenModelArchive::CodegenModelArchive(std::string_view dbPath)
}
}
- // This database is used for a buildsystem and can be regenerated at any time. We don't care for the slightest about data integrity, we just want fast updates
// NOTE: These pragmas are not persistent, so we need to set them every time
+ // SQLite3 as of 2022-06-24 defaults to foreign_keys = OFF, we need this to be on for ON DELETE CASCADE and etc. to work
+ sqlite3_exec(m->database, "PRAGMA foreign_keys = ON", nullptr, nullptr, nullptr);
+ // This database is used for a buildsystem and can be regenerated at any time. We don't care for the slightest about data integrity, we just want fast updates
sqlite3_exec(m->database, "PRAGMA synchronous = OFF", nullptr, nullptr, nullptr);
sqlite3_exec(m->database, "PRAGMA journal_mode = MEMORY", nullptr, nullptr, nullptr);
@@ -381,6 +401,27 @@ CodegenModelArchive::~CodegenModelArchive() {
delete m;
}
+void CodegenModelArchive::DeleteDeclsRelatedToFile(std::string_view filename) {
+ // -Argument- -Description-
+ // ?1 The filename to delete
+ m->deleteStructDeclByFilenameStmt.InitializeLazily(m->database, "DELETE FROM DeclStructs WHERE FileName = ?1;"sv);
+ m->deleteEnumDeclByFilenameStmt.InitializeLazily(m->database, "DELETE FROM DeclEnums WHERE FileName = ?1;"sv);
+
+ m->BeginTransaction();
+ auto stmtList = {
+ m->deleteStructDeclByFilenameStmt.stmt,
+ m->deleteEnumDeclByFilenameStmt.stmt,
+ };
+ for (auto& stmt : stmtList) {
+ sqlite3_bind_text(stmt, 1, filename.data(), filename.size(), nullptr);
+ int result = sqlite3_step(stmt);
+ assert(result == SQLITE_DONE);
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ }
+ m->CommitTransaction();
+}
+
void CodegenModelArchive::Store(const CodegenModel& cgInput) {
auto& cgm = cgInput.GetPimpl();
@@ -425,35 +466,42 @@ void CodegenModelArchive::StoreEnum(const DeclEnum& decl) {
// ?1 Namespace ID
// ?2 Enum name
// ?3 Enum underlying type
+ // ?4 File containing the enum
m->storeEnumStmt.InitializeLazily(m->database, R"""(
-INSERT INTO DeclEnums(NamespaceRowId, Name, UnderlyingType)
- VALUES (?1, ?2, ?3)
- ON CONFLICT DO UPDATE SET UnderlyingType=?3
- RETURNING rowid;
+INSERT INTO DeclEnums(NamespaceId, Name, UnderlyingType, FileName)
+ VALUES (?1, ?2, ?3, ?4)
+ ON CONFLICT DO UPDATE SET
+ UnderlyingType = ?3,
+ FileName = ?4
+ RETURNING Id;
)"""sv);
// -Argument- -Description-
- // ?1 Container enum's rowid
+ // ?1 Container enum's id
// ?2 Enum element name
// ?3 Enum element value
m->storeEnumElmStmt.InitializeLazily(m->database, R"""(
-INSERT INTO DeclEnumElements(EnumRowId, Name, Value)
+INSERT INTO DeclEnumElements(EnumId, Name, Value)
VALUES (?1, ?2, ?3)
ON CONFLICT DO UPDATE SET Value=?3;
)"""sv);
- // TODO delete non-existent enums
sqlite3_bind_int(m->storeEnumStmt, 1, m->FindNamespace(decl.container));
sqlite3_bind_text(m->storeEnumStmt, 2, decl.name.c_str(), decl.name.size(), nullptr);
sqlite3_bind_text(m->storeEnumStmt, 3, decl.underlyingTypeStr.c_str(), decl.underlyingTypeStr.size(), nullptr);
+ if (decl.sourceFile) {
+ sqlite3_bind_text(m->storeEnumStmt, 4, decl.sourceFile->filename.data(), decl.sourceFile->filename.size(), nullptr);
+ } else {
+ sqlite3_bind_text(m->storeEnumElmStmt, 4, "", 0, nullptr);
+ }
int result = sqlite3_step(m->storeEnumStmt);
assert(result == SQLITE_ROW);
- auto enumRowId = sqlite3_column_int64(m->storeEnumStmt, 0);
+ auto EnumId = sqlite3_column_int64(m->storeEnumStmt, 0);
sqlite3_reset(m->storeEnumStmt);
sqlite3_clear_bindings(m->storeEnumStmt);
for (auto& elm : decl.elements) {
- sqlite3_bind_int64(m->storeEnumElmStmt, 1, enumRowId);
+ sqlite3_bind_int64(m->storeEnumElmStmt, 1, EnumId);
sqlite3_bind_text(m->storeEnumElmStmt, 2, elm.name.c_str(), elm.name.size(), nullptr);
sqlite3_bind_int64(m->storeEnumElmStmt, 3, elm.value);
int result = sqlite3_step(m->storeEnumElmStmt);