-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.cpp
More file actions
118 lines (102 loc) · 3.73 KB
/
main.cpp
File metadata and controls
118 lines (102 loc) · 3.73 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
#include "src/sql/parser.h"
#include "src/sql/analyzer.h"
#include "src/sql/catalog.h"
#include "src/sql/executor.h"
#include "src/sql/tuple.h"
#include "src/storage/buffer_pool.h"
#include "src/storage/disk_manager.h"
#include <cstdint>
#include <filesystem>
#include <iostream>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
// =============================================================================
// End-to-end demo: run a CREATE TABLE, an INSERT, and a SELECT through
// Parser → Analyzer → Executor against a fresh database to exercise the
// full statement cycle.
// =============================================================================
namespace {
const std::string kDbPath = "/tmp/dbms_demo.db";
void printSelectResult(const ExecResult& r) {
// Column widths: max of header length and any value length, with a
// small floor so single-char columns aren't crammed.
std::vector<size_t> widths(r.column_names.size());
for (size_t i = 0; i < r.column_names.size(); ++i) {
widths[i] = std::max<size_t>(3, r.column_names[i].size());
}
for (const auto& row : r.rows) {
for (size_t i = 0; i < row.size(); ++i) {
widths[i] = std::max(widths[i], valueToString(row[i]).size());
}
}
auto pad = [](const std::string& s, size_t w) {
return s + std::string(w - s.size(), ' ');
};
std::cout << " ";
for (size_t i = 0; i < r.column_names.size(); ++i) {
if (i) std::cout << " | ";
std::cout << pad(r.column_names[i], widths[i]);
}
std::cout << "\n ";
for (size_t i = 0; i < widths.size(); ++i) {
if (i) std::cout << "-+-";
std::cout << std::string(widths[i], '-');
}
std::cout << "\n";
for (const auto& row : r.rows) {
std::cout << " ";
for (size_t i = 0; i < row.size(); ++i) {
if (i) std::cout << " | ";
std::cout << pad(valueToString(row[i]), widths[i]);
}
std::cout << "\n";
}
std::cout << " (" << r.rows.size() << " row"
<< (r.rows.size() == 1 ? "" : "s") << ")\n";
}
// Run one statement end-to-end. Picks a render based on the parsed
// statement kind: SELECT prints a padded table, CREATE TABLE / INSERT
// print a Postgres-style command tag.
void runStatement(Catalog& cat, BufferPool& bp, const std::string& sql) {
std::cout << "\nSQL: " << sql << "\n";
try {
Parser p(sql);
Statement stmt = p.parse();
Analyzer az(cat);
BoundStatement bound = az.analyzeStatement(stmt);
Executor ex(&bp, &cat);
ExecResult r = ex.execute(std::move(bound));
if (std::holds_alternative<SelectQuery>(stmt)) {
printSelectResult(r);
} else if (std::holds_alternative<CreateTableStmt>(stmt)) {
std::cout << " CREATE TABLE\n";
} else {
std::cout << " INSERT " << r.rows_affected << "\n";
}
} catch (const std::exception& e) {
std::cout << " error: " << e.what() << "\n";
}
}
} // namespace
int main() {
std::error_code ec;
std::filesystem::remove(kDbPath, ec);
DiskManager dm(kDbPath);
BufferPool bp(8, &dm);
// Catalog::create allocates the system-table bootstrap pages
// (__tables at page 0, __columns at page 1) — user tables are
// built via SQL below.
Catalog cat = Catalog::create(&bp);
runStatement(cat, bp,
"CREATE TABLE users (id INT NOT NULL, "
"name TEXT NOT NULL, age INT NOT NULL)");
runStatement(cat, bp,
"INSERT INTO users VALUES "
"(1, 'alice', 30), (2, 'bob', 25), (3, 'carol', 40)");
runStatement(cat, bp, "SELECT * FROM users");
bp.flushAll();
std::filesystem::remove(kDbPath, ec);
return 0;
}