sqlite_stub_maker - pbujak/Sqlite-AddOns GitHub Wiki
The stub database and C++ code generator
It is a command line tool, that parses SQL script with DDL commands creating tables, views, indexes and triggers. The SQL script can contain also unit-tests for triggers, in this case can be for example INSERT/DELETE commands related to views with INSTEAD OF triggers.
Usage:
sqlite_stub_maker sql_ddl_script.sql -o target_stub_database.db3 -c code_generation_directory
This kind of SQL provides the following extensions, that can be useful in unit tests:
- Assertions - when the condition is not satisied the error is generated:
ASSERT SELECT COUNT(*) FROM MyDataTable > 0;
- Variables - the T-SQL like variable can hold the result from the previous command and be later used in the next one.
SET @id = SELECT ID FROM Table2 ORDER BY ID DESC LIMIT 1;
UPDATE Table2 SET Name="Peter" WHERE ID=@id;
Both variables and assertions cannot be used inside triggers.
The first line of SQL script should have an --#include-orm-mappings metacommand to include XML file with ORM mappings between database and C++ code.
--#include-orm-mappings "orm-mappings.xml"
The XML file should have the following structure:
Both SQL and XML could be found in code subdirectory sqlite_addon_examples.
The internal leverage
- The main function in sqlite_stub_maker.cpp parses arguments (sources arguments.* ).
- The SQL file is loaded into memory by function loadSqlScript (sources load_sql_script.* ). The metacommand --#include_orm_mappings is parsed inside.
- The XML file with ORM mappings is loaded by function loadOrmMappings (sources load_orm_mappings.*, xml_node*.* ).
- The in-memory SQLite database is created while parsing the previously loaded SQL script using function buildSqliteDatabase ( sources build_sqlite_database.*, split_sql_into_commands.*, sql_engine.*, sql_lint.* ).
- The SQL is splitted into particular SQL commands (comment blocks are skipped) - at the same time the next command is taken.
- The just taken SQL command is pushed into SQL engine SqlEngine. The engine executes command regarding variables, assertions and assignments. But in case of view creation the correctness of accompanying SELECT is additionally checked in special manner, because SQLite does not check it itself as early as needed.
- After executing the SQL command the lint is executed (SqlLint) to generate warnings related to common mistakes.
- The final state of database is check by lint at the end of the process.
- The ORM mappings resolution against in-memory SQLite database is performed by resolveOrmMappings (sources resolve_orm_mappings.* ) in order to check consistency between database and ORM mappings XML and detect type of fields.
- The in-memory database is dumped into target file.
- The target code is generated
- The C++ source template (so called "metasource") is located in file code_gen_template.hpp. But before compilation it is translated by the prebuild.sh script into the gen/code_gen_template_i.hpp file, that is directly used by compiler. But this step is platform dependent, on Windows it could be managed differently.
- The C++ metasource contains special macros. The macros are resolved during generation by the CodeMacroDictionary class (code_macro_dictionary.cpp file).
- The example of generated code could be seen here: db_unit_record.hpp. The IsModifiable boolean attribute for Bindings tells if the table/view can be modified. It is true for all tables and views with implemented INSTEAD OF triggers. Otherwise it is false.
The deployment and building
The project can be offhand loaded by Eclipse with the CDT add-on. Besides there are two versions Debug, and Release. In each of them there is a ready makefile, that can be used by the "make" tool. But the script prebuild.sh should be used before the actual build to update