Skip to content

Commit a860d43

Browse files
committed
Basic support for emitting SQL queries
TODO: Emit the WHERE clause from dag.
1 parent 14f6311 commit a860d43

7 files changed

+150
-28
lines changed

CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ set(_SOURCE_FILES
3434
sqlgen.cpp
3535
SQLEmitter.cpp
3636
SQLInsertEmitter.cpp
37+
SQLQueryEmitter.cpp
3738
SQLTableEmitter.cpp
3839
)
3940

Error.cpp

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
#include "Error.h"
22

3-
using namespace llvm;
3+
char llvm::SMLocError::ID = 0;
44

5-
char SMLocError::ID = 0;
6-
7-
Error llvm::createTGStringError(SMLoc Loc, const Twine &S) {
5+
llvm::Error llvm::createTGStringError(SMLoc Loc, const Twine &S) {
86
return make_error<SMLocError>(Loc, inconvertibleErrorCode(), S);
97
}

Error.h

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1+
#ifndef SQLGEN_ERROR_H
2+
#define SQLGEN_ERROR_H
13
#include "llvm/ADT/Twine.h"
24
#include "llvm/Support/Error.h"
35
#include "llvm/Support/SMLoc.h"
46

57
namespace llvm {
6-
class SMLocError : public ErrorInfo<SMLocError, StringError> {
7-
using ErrorInfo<SMLocError, StringError>::ErrorInfo;
8-
9-
public:
8+
struct SMLocError : public ErrorInfo<SMLocError, StringError> {
109
static char ID;
1110
SMLoc Loc;
1211

@@ -16,3 +15,4 @@ class SMLocError : public ErrorInfo<SMLocError, StringError> {
1615

1716
Error createTGStringError(SMLoc Loc, const Twine &S);
1817
} // end namespace llvm
18+
#endif

SQLEmitter.cpp

+31-20
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,44 @@
44
#include "llvm/TableGen/Record.h"
55

66
#include "SQLInsertEmitter.h"
7+
#include "SQLQueryEmitter.h"
78
#include "SQLTableEmitter.h"
89

910
using namespace llvm;
1011

1112
Error emitSQL(raw_ostream &OS, RecordKeeper &Records) {
1213

13-
// Generate SQL tables
14-
const auto &Classes = Records.getClasses();
15-
SmallVector<const Record *, 4> TableClasses;
16-
for (const auto &P : Classes) {
17-
if (P.second->isSubClassOf("Table"))
18-
TableClasses.push_back(P.second.get());
14+
if (const auto *TableClass = Records.getClass("Table")) {
15+
// Generate SQL tables
16+
const auto &Classes = Records.getClasses();
17+
SmallVector<const Record *, 4> TableClasses;
18+
for (const auto &P : Classes) {
19+
if (P.second->isSubClassOf(TableClass))
20+
TableClasses.push_back(P.second.get());
21+
}
22+
SQLTableEmitter TableEmitter(OS);
23+
if (auto E = TableEmitter.run(TableClasses))
24+
return std::move(E);
25+
26+
auto getPrimaryKey = [&](const Record *Class) -> Optional<StringRef> {
27+
return TableEmitter.getPrimaryKey(Class);
28+
};
29+
30+
// Generate SQL rows
31+
auto SQLRows = Records.getAllDerivedDefinitions("Table");
32+
// RecordKeeper::getAllDerivedDefinitions will only
33+
// return concrete records, so we don't need to filter out
34+
// class `Record` instances.
35+
if (auto E = SQLInsertEmitter(OS, getPrimaryKey).run(SQLRows))
36+
return std::move(E);
37+
}
38+
39+
if (Records.getClass("Operator") && Records.getClass("Query")) {
40+
auto SQLOperators = Records.getAllDerivedDefinitions("Operator");
41+
auto SQLQueries = Records.getAllDerivedDefinitions("Query");
42+
if (auto E = SQLQueryEmitter(OS).run(SQLQueries, SQLOperators))
43+
return std::move(E);
1944
}
20-
SQLTableEmitter TableEmitter(OS);
21-
if (auto E = TableEmitter.run(TableClasses))
22-
return std::move(E);
23-
24-
auto getPrimaryKey = [&](const Record *Class) -> Optional<StringRef> {
25-
return TableEmitter.getPrimaryKey(Class);
26-
};
27-
28-
// RecordKeeper::getAllDerivedDefinitions will only
29-
// return concrete records, so we don't need to filter out
30-
// class `Record` instances.
31-
auto SQLRows = Records.getAllDerivedDefinitions("Table");
32-
if (auto E = SQLInsertEmitter(OS, getPrimaryKey).run(SQLRows))
33-
return std::move(E);
3445

3546
return Error::success();
3647
}

SQLQueryEmitter.cpp

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#include "llvm/ADT/StringExtras.h"
2+
#include "llvm/ADT/StringMap.h"
3+
#include "Error.h"
4+
#include "SQLQueryEmitter.h"
5+
6+
using namespace llvm;
7+
8+
namespace {
9+
class SQLWhereClauseEmitter {
10+
raw_ostream &OS;
11+
12+
public:
13+
SQLWhereClauseEmitter(raw_ostream &OS) : OS(OS) {}
14+
15+
Error run(const DagInit *WhereClause);
16+
};
17+
} // end anonymous namespace
18+
19+
Error SQLWhereClauseEmitter::run(const DagInit *WhereClause) {
20+
// TODO: Build an operator tree and visit it in an infix fashion.
21+
return Error::success();
22+
}
23+
24+
Error SQLQueryEmitter::run(ArrayRef<const Record *> Queries,
25+
ArrayRef<const Record *> Operators) {
26+
// Map from the tag name to its corresponding SQL table field name.
27+
StringMap<StringRef> FieldTagMap;
28+
29+
for (const auto *QueryRecord : Queries) {
30+
auto MaybeTableName = QueryRecord->getValueAsOptionalString("TableName");
31+
if (!MaybeTableName || MaybeTableName->empty())
32+
return createTGStringError(QueryRecord->getLoc()[0], "SQL table name "
33+
"is missing");
34+
auto TableName = *MaybeTableName;
35+
36+
OS << "SELECT ";
37+
38+
const DagInit *FieldsInit = QueryRecord->getValueAsDag("Fields");
39+
auto FieldOpName = FieldsInit->getOperator()->getAsString();
40+
if (FieldOpName == "all")
41+
OS << "*";
42+
else if (FieldOpName != "fields")
43+
// FIXME: This is a terrible SMLoc to use here.
44+
return createTGStringError(QueryRecord->getLoc()[0], "Invalid dag operator"
45+
" \"" + FieldOpName + "\"");
46+
47+
FieldTagMap.clear();
48+
{
49+
ListSeparator LS;
50+
for (unsigned i = 0U; i != FieldsInit->arg_size(); ++i)
51+
if (const auto *Field = dyn_cast<StringInit>(FieldsInit->getArg(i))) {
52+
OS << LS << Field->getValue();
53+
if (const auto *Tag = FieldsInit->getArgName(i))
54+
FieldTagMap.insert({Tag->getValue(), Field->getValue()});
55+
}
56+
}
57+
58+
OS << " FROM " << TableName;
59+
60+
const DagInit *WhereClause = QueryRecord->getValueAsDag("WhereClause");
61+
if (WhereClause->getOperator()->getAsString() != "none") {
62+
OS << "\n";
63+
if (auto E = SQLWhereClauseEmitter(OS).run(WhereClause))
64+
return std::move(E);
65+
}
66+
67+
auto OrderedBy = QueryRecord->getValueAsListOfStrings("OrderedBy");
68+
if (OrderedBy.size()) {
69+
OS << "\n";
70+
OS << "ORDER BY ";
71+
ListSeparator LS;
72+
for (auto FieldOrTag : OrderedBy) {
73+
auto FieldName = FieldOrTag;
74+
if (FieldOrTag.startswith("$")) {
75+
// It's a tag
76+
auto TagName = FieldOrTag.drop_front(1);
77+
auto I = FieldTagMap.find(TagName);
78+
if (I == FieldTagMap.end())
79+
return createTGStringError(QueryRecord->getLoc()[0], "Unrecognized "
80+
"tag \"" + TagName + "\"");
81+
FieldName = I->second;
82+
}
83+
OS << LS << FieldName;
84+
}
85+
}
86+
87+
OS << ";\n\n";
88+
}
89+
90+
return Error::success();
91+
}

SQLQueryEmitter.h

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#ifndef SQLGEN_SQLQUERYEMITTER_H
2+
#define SQLGEN_SQLQUERYEMITTER_H
3+
#include "llvm/ADT/ArrayRef.h"
4+
#include "llvm/Support/Error.h"
5+
#include "llvm/Support/raw_ostream.h"
6+
#include "llvm/TableGen/Record.h"
7+
8+
namespace llvm {
9+
class SQLQueryEmitter {
10+
raw_ostream &OS;
11+
12+
public:
13+
explicit
14+
SQLQueryEmitter(raw_ostream &OS) : OS(OS) {}
15+
16+
Error run(ArrayRef<const Record *> Queries,
17+
ArrayRef<const Record *> Operators);
18+
};
19+
} // end namespace llvm
20+
#endif

SQLTableEmitter.h

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class SQLTableEmitter {
1212
DenseMap<const Record *, StringRef> PrimaryKeys;
1313

1414
public:
15+
explicit
1516
SQLTableEmitter(raw_ostream &OS) : OS(OS) {}
1617

1718
Error run(ArrayRef<const Record *> Classes);

0 commit comments

Comments
 (0)