-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexample.cpp
More file actions
174 lines (144 loc) · 5.81 KB
/
example.cpp
File metadata and controls
174 lines (144 loc) · 5.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
// Copyright (c) 2026 Yang Zhengguo. All Rights Reserved.
//
// Compile command example:
// g++ -std=c++17 example.cc easy_mysql.cc -o example -lmysqlcppconn
#include <iostream>
#include <vector>
#include <iomanip>
#include "easy_mysql.h"
using namespace easymysql;
// --- Helper: Custom Logger ---
void ConsoleLogger(LogLevel level, const std::string& msg) {
switch (level) {
case LogLevel::kInfo:
std::cout << "[INFO] " << msg << std::endl;
break;
case LogLevel::kWarning:
std::cout << "\033[33m[WARN] " << msg << "\033[0m" << std::endl; // Yellow
break;
case LogLevel::kError:
std::cerr << "\033[31m[ERROR] " << msg << "\033[0m" << std::endl; // Red
break;
case LogLevel::kDebug:
// std::cout << "[DEBUG] " << msg << std::endl;
break;
}
}
// --- Helper: Print Divider ---
void PrintSection(const std::string& title) {
std::cout << "\n--------------------------------------------------\n";
std::cout << ">>> " << title << "\n";
std::cout << "--------------------------------------------------\n";
}
// --- Demo: Transaction Auto-Rollback ---
// This function demonstrates RAII. We insert a record but "forget" to commit.
void SimulateFailedTransaction(EasyMySQL& db) {
std::cout << " -> Starting temporary transaction scope...\n";
// 1. Create Transaction Guard
auto trans = db.CreateTransaction();
// 2. Execute SQL
int64_t ret = db.Execute("INSERT INTO test_users (name, balance) VALUES (?, ?)", "Ghost User", 9999);
if (ret > 0) {
std::cout << " -> Inserted 'Ghost User' inside transaction (Pending Commit).\n";
}
// 3. Simulate an error or early return
std::cout << " -> ! Simulating an error/exception before commit ! \n";
return;
// 4. Scope ends here. 'trans' destructor is called.
// Since trans.Commit() was never called, it performs a ROLLBACK.
}
int main() {
// 1. Initialization
EasyMySQL db;
db.SetLogger(ConsoleLogger);
// 2. Connection Config (Modify these to match your local setup)
DbConfig config;
config.host = "127.0.0.1";
config.port = 3306;
config.user = "root";
config.password = "123456";
config.database = "test_db";
// Note: Make sure 'test_db' exists, or connect to 'mysql' and create it.
PrintSection("Connecting to Database");
if (!db.Connect(config)) {
std::cerr << "Failed to connect. Please check your config." << std::endl;
return -1;
}
// 3. Setup Environment (DDL)
PrintSection("Setting up Table");
db.Execute("DROP TABLE IF EXISTS test_users");
db.Execute(R"(
CREATE TABLE test_users (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100),
balance DOUBLE,
notes TEXT
)
)");
std::cout << "Table 'test_users' created.\n";
// 4. Basic Insert with Parameter Binding
PrintSection("Inserting Data");
// Case A: Standard types
db.Execute("INSERT INTO test_users (name, balance, notes) VALUES (?, ?, ?)",
"Alice", 1000.50, "Regular customer");
// Case B: Testing Special Characters (The user's question about '?')
// This string contains SQL keywords and question marks.
// Because we use PreparedStatement, this is perfectly safe.
std::string tricky_string = "Hello? Is this SQL safe? OR 1=1 --";
db.Execute("INSERT INTO test_users (name, balance, notes) VALUES (?, ?, ?)",
"Hacker?", 0.0, tricky_string);
std::cout << "Inserted 2 rows.\n";
// 5. Querying Data
PrintSection("Querying Data");
auto print_rows = [&](sql::ResultSet* res) {
std::cout << std::left << std::setw(5) << "ID"
<< std::setw(15) << "Name"
<< std::setw(10) << "Balance"
<< "Notes" << std::endl;
while (res->next()) {
std::cout << std::left << std::setw(5) << res->getInt("id")
<< std::setw(15) << res->getString("name")
<< std::setw(10) << res->getDouble("balance")
<< res->getString("notes") << std::endl;
}
return true;
};
db.Query("SELECT * FROM test_users", print_rows);
// 6. Transaction: Successful Commit
PrintSection("Transaction Test: Success (Commit)");
{
auto trans = db.CreateTransaction();
std::cout << " -> Transferring 100.0 from Alice to Hacker?...\n";
db.Execute("UPDATE test_users SET balance = balance - ? WHERE name = ?", 100.0, "Alice");
db.Execute("UPDATE test_users SET balance = balance + ? WHERE name = ?", 100.0, "Hacker?");
if (trans.Commit()) {
std::cout << " -> Transaction Committed Successfully.\n";
} else {
std::cout << " -> Commit Failed.\n";
}
}
// 7. Transaction: Auto-Rollback (RAII)
PrintSection("Transaction Test: Failure (Auto-Rollback)");
// Check count before
int count_before = 0;
db.Query("SELECT COUNT(*) FROM test_users", [&](sql::ResultSet* res){
if(res->next()) count_before = res->getInt(1);
return true;
});
std::cout << " Rows before: " << count_before << "\n";
// Run the function that fails to commit
SimulateFailedTransaction(db);
// Check count after
int count_after = 0;
db.Query("SELECT COUNT(*) FROM test_users", [&](sql::ResultSet* res){
if(res->next()) count_after = res->getInt(1);
return true;
});
std::cout << " Rows after : " << count_after << "\n";
if (count_before == count_after) {
std::cout << " [SUCCESS] Data was rolled back correctly. 'Ghost User' does not exist.\n";
} else {
std::cout << " [FAILURE] Data was not rolled back!\n";
}
return 0;
}