From 9801880a0fe2a72ecbf0aa3b63a4c978a321dbe7 Mon Sep 17 00:00:00 2001 From: Brett Laptop Date: Wed, 12 Mar 2025 18:46:20 -0400 Subject: [PATCH] silly little poorly designed converter --- .gitignore | 1 + .idea/.gitignore | 8 + .idea/editor.xml | 527 ++++++++++++++++++++++++++++++++++++++++ .idea/misc.xml | 7 + .idea/modules.xml | 8 + .idea/sql-converter.iml | 2 + .idea/vcs.xml | 9 + CMakeLists.txt | 2 +- lib/blt | 2 +- src/main.cpp | 327 ++++++++++++++++++++++++- 10 files changed, 888 insertions(+), 5 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/editor.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/sql-converter.iml create mode 100644 .idea/vcs.xml diff --git a/.gitignore b/.gitignore index 0ad02d1..a9bb76d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ out/ ./cmake-build*/ ./build/ ./out/ +test/ diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/editor.xml b/.idea/editor.xml new file mode 100644 index 0000000..bf1be31 --- /dev/null +++ b/.idea/editor.xml @@ -0,0 +1,527 @@ + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..0b76fe5 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..83b63b4 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/sql-converter.iml b/.idea/sql-converter.iml new file mode 100644 index 0000000..f08604b --- /dev/null +++ b/.idea/sql-converter.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..961de5a --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 9650fed..889e0c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,7 +49,7 @@ macro(blt_add_project name source type) project(sql-converter) endmacro() -project(sql-converter VERSION 0.0.2) +project(sql-converter VERSION 0.0.3) option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF) option(ENABLE_UBSAN "Enable the ub sanitizer" OFF) diff --git a/lib/blt b/lib/blt index 8c88c62..04a5c01 160000 --- a/lib/blt +++ b/lib/blt @@ -1 +1 @@ -Subproject commit 8c88c6296f817d7c86d5089b4050fac258eb337a +Subproject commit 04a5c01704bbf126ef623d57af61359cdf3d659c diff --git a/src/main.cpp b/src/main.cpp index 6f2b004..3326dec 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,327 @@ -#include +#define BLT_DISABLE_TRACE +#include +#include +#include +#include +#include +#include -int main() +enum class case_t { - std::cout << "Hello World!" << std::endl; + UPPERCASE, LOWERCASE +}; + +blt::hashset_t sqlite_keywords{ + "ABORT", + "ACTION", + "ADD", + "AFTER", + "ALL", + "ALTER", + "ALWAYS", + "ANALYZE", + "AND", + "AS", + "ASC", + "ATTACH", + "AUTOINCREMENT", + "BEFORE", + "BEGIN", + "BETWEEN", + "BY", + "CASCADE", + "CASE", + "CAST", + "CHECK", + "COLLATE", + "COLUMN", + "COMMIT", + "CONFLICT", + "CONSTRAINT", + "CREATE", + "CROSS", + "CURRENT", + "CURRENT_DATE", + "CURRENT_TIME", + "CURRENT_TIMESTAMP", + "DATABASE", + "DEFAULT", + "DEFERRABLE", + "DEFERRED", + "DELETE", + "DESC", + "DETACH", + "DISTINCT", + "DO", + "DROP", + "EACH", + "ELSE", + "END", + "ESCAPE", + "EXCEPT", + "EXCLUDE", + "EXCLUSIVE", + "EXISTS", + "EXPLAIN", + "FAIL", + "FILTER", + "FIRST", + "FOLLOWING", + "FOR", + "FOREIGN", + "FROM", + "FULL", + "GENERATED", + "GLOB", + "GROUP", + "GROUPS", + "HAVING", + "IF", + "IGNORE", + "IMMEDIATE", + "IN", + "INDEX", + "INDEXED", + "INITIALLY", + "INNER", + "INSERT", + "INSTEAD", + "INTERSECT", + "INTO", + "IS", + "ISNULL", + "JOIN", + "KEY", + "LAST", + "LEFT", + "LIKE", + "LIMIT", + "MATCH", + "NATURAL", + "NO", + "NOT", + "NOTHING", + "NOTNULL", + "NULL", + "NULLS", + "OF", + "OFFSET", + "ON", + "OR", + "ORDER", + "OTHERS", + "OUTER", + "OVER", + "PARTITION", + "PLAN", + "PRAGMA", + "PRECEDING", + "PRIMARY", + "QUERY", + "RAISE", + "RANGE", + "RECURSIVE", + "REFERENCES", + "REGEXP", + "REINDEX", + "RELEASE", + "RENAME", + "REPLACE", + "RESTRICT", + "RIGHT", + "ROLLBACK", + "ROW", + "ROWS", + "SAVEPOINT", + "SELECT", + "SET", + "TABLE", + "TEMP", + "TEMPORARY", + "THEN", + "TIES", + "TO", + "TRANSACTION", + "TRIGGER", + "UNBOUNDED", + "UNION", + "UNIQUE", + "UPDATE", + "USING", + "VACUUM", + "VALUES", + "VIEW", + "VIRTUAL", + "WHEN", + "WHERE", + "WINDOW", + "WITH", + "WITHOUT", + "RETURNING" +}; + +blt::logging::status_progress_bar_t progress; + +double number_of_files = 1; +double processed_files = 0; + +void process_file(std::optional search, const std::string& file, case_t c) +{ + auto file_data = blt::fs::getFile(file); + size_t last_pos = 0; + size_t pos = 0; + + if (!search) + search = "\""; + + while ((pos = file_data.find(*search, last_pos)) != std::string::npos) + { + const auto begin = file_data.find('"', pos); + size_t end = begin; + for (size_t i = begin + 1; i < file_data.size(); i++) + { + if (file_data[i] == '"' && file_data[i - 1] != '\\') + { + end = i; + break; + } + } + if (end == begin) + { + BLT_WARN("Unable to process SQL statement, at char pos {}, local string looks like '{}'", pos, std::string_view( + file_data.data() + std::max(static_cast(pos) - 10, 0l), std::min(20ul, file_data.size() - pos - 10))); + last_pos = end + 1; + continue; + } + + size_t space_pos = file_data.find(' ', begin); + size_t last_space = space_pos; + + auto substr = blt::string::toUpperCase(file_data.substr(begin + 1, space_pos - begin - 1)); + BLT_TRACE("Found substring '{}' at {} until {}", substr, begin + 1, space_pos - 1); + + if (sqlite_keywords.contains(substr)) + { + switch (c) + { + case case_t::UPPERCASE: + file_data.replace(begin + 1, substr.size(), substr); + break; + case case_t::LOWERCASE: + file_data.replace(begin + 1, substr.size(), blt::string::toLowerCase(substr)); + break; + } + } + + while (((space_pos = file_data.find(' ', last_space + 1)) != std::string::npos) && space_pos < end) + { + substr = blt::string::toUpperCase(file_data.substr(last_space + 1, space_pos - last_space - 1)); + BLT_TRACE("Found substring '{}' at {} until {}", substr, last_space + 1, last_space + 1 + substr.size()); + + if (sqlite_keywords.contains(substr)) + { + switch (c) + { + case case_t::UPPERCASE: + file_data.replace(last_space + 1, substr.size(), substr); + break; + case case_t::LOWERCASE: + file_data.replace(last_space + 1, substr.size(), blt::string::toLowerCase(substr)); + break; + } + } + + last_space = space_pos; + } + + substr = blt::string::toUpperCase(file_data.substr(last_space + 1, end - last_space - 1)); + BLT_TRACE("Found substring '{}' at {} until {}", substr, last_space + 1, last_space + 1 + substr.size()); + + if (sqlite_keywords.contains(substr)) + { + switch (c) + { + case case_t::UPPERCASE: + file_data.replace(last_space + 1, substr.size(), substr); + break; + case case_t::LOWERCASE: + file_data.replace(last_space + 1, substr.size(), blt::string::toLowerCase(substr)); + break; + } + } + + BLT_DEBUG("Processed SQL statement at pos {}", pos); + last_pos = end + 1; + } + ++processed_files; + progress.set_progress(processed_files / number_of_files); + std::ofstream out(file, std::ios::out); + out.write(file_data.data(), static_cast(file_data.size())); + BLT_INFO("Processed file {}", file); +} + +void process_directory(const std::optional& search, const std::string& dir, case_t c) +{ + std::vector files_to_process; + std::vector directories_to_process; + directories_to_process.push_back(dir); + while (!directories_to_process.empty()) + { + const auto local_dir = directories_to_process.back(); + directories_to_process.pop_back(); + BLT_DEBUG("Processing directory '{}'", local_dir); + for (auto& file : std::filesystem::directory_iterator(local_dir)) + { + if (file.is_directory()) + directories_to_process.push_back(file.path().string()); + else + files_to_process.push_back(file.path().string()); + } + } + number_of_files = static_cast(files_to_process.size()); + for (const auto& file : files_to_process) + process_file(search, file, c); +} + +int main(const int argc, const char** argv) +{ + blt::logging::status_bar_t status; + blt::logging::get_global_config().add_injector(status.add(progress)); + + blt::argparse::argument_parser_t parser{"Rename SQL statements to be of a case."}; + parser.with_help(); + parser.with_version(); + parser.add_flag("-r", "--recursive").set_dest("-r").make_flag().set_help("Treat path as a directory and recursively iterate through it."); + parser.add_flag("-u", "--uppercase").set_dest("-u").make_flag().set_help("Make SQL statements uppercase. This is the default option"); + parser.add_flag("-l", "--lowercase").set_dest("-l").make_flag().set_help("Make SQL statements lowercase."); + parser.add_positional("path").set_help("Path to the file or directory to process."); + parser.add_positional("search").set_help( + "Search string for parser to lock onto for SQL replacement. " + "This should be everything BEFORE the first \" (Do not include the double quote)").set_required(false); + + const auto args = parser.parse(argc, argv); + + if (args.get("-u") && args.get("-l")) + { + BLT_ERROR("Cannot use both uppercase and lowercase flags at the same time"); + return 1; + } + + auto c = case_t::UPPERCASE; + + if (args.get("-u")) + c = case_t::UPPERCASE; + if (args.get("-l")) + c = case_t::LOWERCASE; + + BLT_INFO("Running on path '{}'", args.get("path")); + + std::optional search; + if (args.contains("search")) + search = args.get("search"); + + if (args.get("-r")) + process_directory(search, args.get("path"), c); + else + process_file(search, args.get("path"), c); }