diff options
author | rtk0c <[email protected]> | 2022-06-24 17:34:56 -0700 |
---|---|---|
committer | rtk0c <[email protected]> | 2022-06-24 17:34:56 -0700 |
commit | fd66e74445f50426aa8a137b0a9cfa6d088b953c (patch) | |
tree | 6e5d2557f567a7e11a7cc83612af482f27481a3a /source/20-codegen-compiler/CodegenModel.cpp | |
parent | 4386c02d61b37c0d5c508895df2f028b8ea2057c (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.cpp | 106 |
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); |