adds prepared insert statements
This commit is contained in:
parent
5f29d179d7
commit
75ad36cb37
|
@ -1,5 +1,5 @@
|
|||
CXX = g++
|
||||
CXXFLAGS = -std=c++20 -Wall -pedantic -fsanitize=address -g
|
||||
CXXFLAGS = -std=c++20 -Wall -pedantic -O2
|
||||
LDFLAGS = -lsqlite3
|
||||
|
||||
SRCS = $(wildcard *.cpp)
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include <sqlite3.h>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
|
||||
#define RESET "\033[0m"
|
||||
#define RED "❌ \033[31m"
|
||||
|
@ -13,6 +15,8 @@ constexpr const char* MENU_PREP_MSG = "=== Prepared Statement Menu: Select state
|
|||
constexpr const char* MENU_PREP_COL_MSG = "=== Prepared Statement Menu: Select filter culumn ===\n1. Connect to database\n2. Execute custom SQL query\n3. Execute prepared SQL query\n4. Setup demo database\n5. Exit\n";
|
||||
constexpr const char* MENU_PREP_TYPE_MSG = "=== Prepared Statement Menu: Select filter type ===\n1. Connect to database\n2. Execute custom SQL query\n3. Execute prepared SQL query\n4. Setup demo database\n5. Exit\n";
|
||||
|
||||
constexpr const char* PREP_STATEMENT = "INSERT INTO users (FirstName, LastName, Age) VALUES (?, ?, ?)";
|
||||
|
||||
constexpr const char* DEMO_CREATE_TABLE = "CREATE TABLE IF NOT EXISTS users (ID INTEGER PRIMARY KEY AUTOINCREMENT, FirstName varchar(255) NOT NULL, LastName varchar(255) NOT NULL, Age int);";
|
||||
constexpr const char* DEMO_INSERT1 = "INSERT INTO users (FirstName, LastName, Age) VALUES ('Tedd', 'Chadwick', 23)";
|
||||
constexpr const char* DEMO_INSERT2 = "INSERT INTO users (FirstName, LastName, Age) VALUES ('Kathe', 'Claris', 31)";
|
||||
|
@ -22,10 +26,10 @@ constexpr const char* DEMO_SELECT2 = "SELECT * FROM users WHERE LastName is 'Cha
|
|||
|
||||
class DatabaseException : public std::exception {
|
||||
public:
|
||||
explicit DatabaseException() = default;
|
||||
explicit DatabaseException() : errMsg(nullptr) {}
|
||||
DatabaseException(const char *errMsg) : errMsg(errMsg) {}
|
||||
const char* what() const noexcept override {
|
||||
return "Internal exception!";
|
||||
return errMsg ? errMsg : "Internal error!";
|
||||
}
|
||||
private:
|
||||
const char *errMsg;
|
||||
|
@ -57,30 +61,6 @@ enum class MenuState {
|
|||
EXIT = 5,
|
||||
};
|
||||
|
||||
enum class StatementMenuState {
|
||||
MENU,
|
||||
SELECT = 1,
|
||||
INSERT = 2,
|
||||
EXIT = 3,
|
||||
};
|
||||
|
||||
enum class ColumnMenuState {
|
||||
MENU,
|
||||
FIRST_NAME = 1,
|
||||
SECOND_NAME = 2,
|
||||
AGE = 3,
|
||||
EXIT = 4,
|
||||
};
|
||||
|
||||
enum class FilterMenuState {
|
||||
MENU,
|
||||
IS = 1,
|
||||
IS_NOT = 2,
|
||||
LESS = 3,
|
||||
GREATER = 4,
|
||||
EXIT = 5,
|
||||
};
|
||||
|
||||
std::istream& operator>>(std::istream& is, MenuState& state) {
|
||||
int a;
|
||||
if (!(is >> a)) {
|
||||
|
@ -127,17 +107,17 @@ bool sendQuery(sqlite3* db, std::ostream& os, const char* q, int (*callback)(voi
|
|||
char* errMsg;
|
||||
void* os_p = &os; // oh god...
|
||||
|
||||
os << "Sending query: '" << q << "'...";
|
||||
os << "Sending query: '" << q << "'\n";
|
||||
rc = sqlite3_exec(db, q, callback, os_p, &errMsg);
|
||||
if (rc != SQLITE_OK) {
|
||||
throw SQLiteException(errMsg);
|
||||
}
|
||||
os << GREEN << "Successful\n" << RESET;
|
||||
os << GREEN << "Successful\n\n" << RESET;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool setupDemo(sqlite3** db, std::ostream& os) {
|
||||
dbConnect(db, os);
|
||||
if (!*db) dbConnect(db, os);
|
||||
|
||||
os << "Creating table 'users':\n";
|
||||
sendQuery(*db, os, DEMO_CREATE_TABLE, nullptr);
|
||||
|
@ -154,12 +134,38 @@ bool setupDemo(sqlite3** db, std::ostream& os) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool preparedStatementMenu(sqlite3* db, std::ostream& os, std::istream& is) {
|
||||
return true;
|
||||
}
|
||||
bool executePrepared(sqlite3* db, std::ostream& os, std::istream& is) {
|
||||
sqlite3_stmt *ppStmt;
|
||||
int rc;
|
||||
|
||||
bool executePrepared(sqlite3* db, std::ostream& os) {
|
||||
std::string fn;
|
||||
std::string ln;
|
||||
int age;
|
||||
|
||||
os << "First name: ";
|
||||
is >> fn; if (std::any_of(fn.begin(), fn.end(), [](auto c){ return !std::isalpha(c); })) throw DatabaseException("Invalid name!");
|
||||
os << "Last name: ";
|
||||
is >> ln; if (std::any_of(ln.begin(), ln.end(), [](auto c){ return !std::isalpha(c); })) throw DatabaseException("Invalid name!");
|
||||
os << "Age (-1 for NULL): ";
|
||||
if (!(is >> age)) age = -1;
|
||||
|
||||
os << "Executing prepared statement: " << PREP_STATEMENT << "\nwith values: "
|
||||
<< fn << ", " << ln << ", " << (age >= 0 ? std::to_string(age) : std::string("NULL")) << "\n";
|
||||
rc = sqlite3_prepare(db, PREP_STATEMENT, 1024, &ppStmt, nullptr);
|
||||
if (rc != SQLITE_OK) throw DatabaseException("Statement cant be prepared!");
|
||||
|
||||
sqlite3_bind_text(ppStmt, 1, fn.c_str(), -1, SQLITE_STATIC);
|
||||
sqlite3_bind_text(ppStmt, 2, ln.c_str(), -1, SQLITE_STATIC);
|
||||
if (age >= 0) sqlite3_bind_int(ppStmt, 3, age);
|
||||
|
||||
rc = sqlite3_step(ppStmt);
|
||||
if (rc != SQLITE_DONE) {
|
||||
throw DatabaseException(sqlite3_errmsg(db));
|
||||
}
|
||||
|
||||
rc = sqlite3_finalize(ppStmt);
|
||||
if (rc != SQLITE_OK) throw DatabaseException("Statement failed!");
|
||||
return rc;
|
||||
}
|
||||
|
||||
int main(int ragc, char* argv[]) {
|
||||
|
@ -192,8 +198,8 @@ int main(int ragc, char* argv[]) {
|
|||
break;
|
||||
|
||||
case MenuState::QUERY_PREPARED :
|
||||
os << "Account number: ";
|
||||
os << GREEN << "Balance: " << "$" << "\n" << RESET;
|
||||
executePrepared(db, os, is);
|
||||
os << "Done\n";
|
||||
break;
|
||||
|
||||
case MenuState::SETUP_DEMO :
|
||||
|
@ -211,11 +217,11 @@ int main(int ragc, char* argv[]) {
|
|||
throw InvalidArgument();
|
||||
}
|
||||
} catch (DatabaseException& e) {
|
||||
os << RED << e.what() << RESET;
|
||||
os << RED << e.what() << "\n" << RESET;
|
||||
// return EXIT_FAILURE;
|
||||
}
|
||||
state = MenuState::MENU;
|
||||
os << "\n\n";
|
||||
os << "\n";
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue