-
Notifications
You must be signed in to change notification settings - Fork 5
/
SQLTableEmitter.cpp
107 lines (94 loc) · 3.05 KB
/
SQLTableEmitter.cpp
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
#include "llvm/ADT/StringExtras.h"
#include "Error.h"
#include "SQLTableEmitter.h"
using namespace llvm;
namespace {
enum class SQLType {
Unknown,
Integer,
VarChar
};
} // end anonymous namespace
namespace llvm {
raw_ostream &operator<<(raw_ostream &OS, const SQLType &Ty) {
switch (Ty) {
case SQLType::Integer:
OS << "int";
break;
case SQLType::VarChar:
OS << "varchar(255)";
break;
default:
break;
}
return OS;
}
} // end namespace llvm
Error SQLTableEmitter::run(ArrayRef<const Record *> Classes) {
// {SQL data type, member name}
SmallVector<std::pair<SQLType, StringRef>, 4> TableMembers;
// {foreign key member, referee class, referee primary key}
SmallVector<std::tuple<StringRef, const Record *, StringRef>, 4>
ForeignKeys;
for (const auto *Class : Classes) {
StringRef CurPrimaryKey;
TableMembers.clear();
ForeignKeys.clear();
for (const auto &RV : Class->getValues()) {
// We only care about member variables.
if (RV.isTemplateArg())
continue;
auto Name = RV.getName();
// The PrimaryKey member is not directly used.
if (Name == "PrimaryKey")
continue;
if (auto *VI = dyn_cast<VarInit>(RV.getValue())) {
if (VI->getName() == "PrimaryKey")
CurPrimaryKey = Name;
}
SQLType SQLTy = SQLType::Unknown;
const auto *RVT = RV.getType();
switch (RVT->getRecTyKind()) {
case RecTy::IntRecTyKind:
case RecTy::RecordRecTyKind:
SQLTy = SQLType::Integer;
if (const auto *RRT = dyn_cast<RecordRecTy>(RVT)) {
// Implement members with RecordRecTy with foreign keys.
bool FoundFK = false;
for (const auto *C : RRT->getClasses())
if (PrimaryKeys.count(C)) {
ForeignKeys.push_back({Name, C, PrimaryKeys[C]});
FoundFK = true;
break;
}
if (!FoundFK)
return createTGStringError(RV.getLoc(), "Cannot locate primary key "
"of the referred table");
}
break;
case RecTy::StringRecTyKind:
SQLTy = SQLType::VarChar;
break;
default:
return createTGStringError(RV.getLoc(),
"Unsupported table member type");
}
TableMembers.push_back({SQLTy, Name});
}
// Write down the primary key of this table.
if (CurPrimaryKey.size())
PrimaryKeys.insert({Class, CurPrimaryKey});
ListSeparator LS(",\n");
OS << "CREATE TABLE " << Class->getName() << " (\n";
for (const auto &Member : TableMembers)
(OS << LS).indent(4) << Member.second << " " << Member.first;
if (CurPrimaryKey.size())
(OS << LS).indent(4) << "PRIMARY KEY (" << CurPrimaryKey << ")";
for (const auto &FK : ForeignKeys)
(OS << LS).indent(4) << "FOREIGN KEY (" << std::get<0>(FK) << ") "
<< "REFERENCES " << std::get<1>(FK)->getName()
<< "(" << std::get<2>(FK) << ")";
OS << "\n);\n\n";
}
return Error::success();
}