Skip to content

Commit 1ea314e

Browse files
committed
feat: add catalog interface, InMemoryCatalog, and resolver bridge to evaluator
1 parent 8082675 commit 1ea314e

6 files changed

Lines changed: 602 additions & 2 deletions

File tree

Makefile.new

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ LIB_OBJS = $(LIB_SRCS:.cpp=.o)
1414
LIB_TARGET = $(PROJECT_ROOT)/libsqlparser.a
1515

1616
# SQL Engine sources
17-
ENGINE_SRCS = $(ENGINE_SRC_DIR)/function_registry.cpp
17+
ENGINE_SRCS = $(ENGINE_SRC_DIR)/function_registry.cpp \
18+
$(ENGINE_SRC_DIR)/in_memory_catalog.cpp
1819
ENGINE_OBJS = $(ENGINE_SRCS:.cpp=.o)
1920

2021
# Google Test library
@@ -49,7 +50,8 @@ TEST_SRCS = $(TEST_DIR)/test_main.cpp \
4950
$(TEST_DIR)/test_registry.cpp \
5051
$(TEST_DIR)/test_like.cpp \
5152
$(TEST_DIR)/test_expression_eval.cpp \
52-
$(TEST_DIR)/test_eval_integration.cpp
53+
$(TEST_DIR)/test_eval_integration.cpp \
54+
$(TEST_DIR)/test_catalog.cpp
5355
TEST_OBJS = $(TEST_SRCS:.cpp=.o)
5456
TEST_TARGET = $(PROJECT_ROOT)/run_tests
5557

include/sql_engine/catalog.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#ifndef SQL_ENGINE_CATALOG_H
2+
#define SQL_ENGINE_CATALOG_H
3+
4+
#include "sql_engine/types.h"
5+
#include "sql_parser/common.h"
6+
#include <cstdint>
7+
8+
namespace sql_engine {
9+
10+
struct ColumnInfo {
11+
sql_parser::StringRef name;
12+
SqlType type;
13+
uint16_t ordinal; // 0-based position in table
14+
bool nullable;
15+
};
16+
17+
struct TableInfo {
18+
sql_parser::StringRef schema_name; // empty if default/no schema
19+
sql_parser::StringRef table_name;
20+
const ColumnInfo* columns;
21+
uint16_t column_count;
22+
};
23+
24+
// Convenience for building columns programmatically
25+
struct ColumnDef {
26+
const char* name;
27+
SqlType type;
28+
bool nullable = true;
29+
};
30+
31+
class Catalog {
32+
public:
33+
virtual ~Catalog() = default;
34+
35+
// Find a table by unqualified name. Returns nullptr if not found.
36+
virtual const TableInfo* get_table(sql_parser::StringRef name) const = 0;
37+
38+
// Find a table by qualified name (schema.table). Returns nullptr if not found.
39+
virtual const TableInfo* get_table(sql_parser::StringRef schema,
40+
sql_parser::StringRef table) const = 0;
41+
42+
// Find a column in a table by name. Returns nullptr if not found.
43+
virtual const ColumnInfo* get_column(const TableInfo* table,
44+
sql_parser::StringRef column_name) const = 0;
45+
};
46+
47+
} // namespace sql_engine
48+
49+
#endif // SQL_ENGINE_CATALOG_H
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#ifndef SQL_ENGINE_CATALOG_RESOLVER_H
2+
#define SQL_ENGINE_CATALOG_RESOLVER_H
3+
4+
#include "sql_engine/catalog.h"
5+
#include "sql_engine/value.h"
6+
7+
namespace sql_engine {
8+
9+
// Create a column resolver callback from catalog + table + row values.
10+
// Returns a std::function<Value(StringRef)> suitable for evaluate_expression().
11+
inline auto make_resolver(const Catalog& catalog,
12+
const TableInfo* table,
13+
const Value* row_values) {
14+
return [&catalog, table, row_values](sql_parser::StringRef col_name) -> Value {
15+
const ColumnInfo* col = catalog.get_column(table, col_name);
16+
if (!col) return value_null();
17+
return row_values[col->ordinal];
18+
};
19+
}
20+
21+
} // namespace sql_engine
22+
23+
#endif // SQL_ENGINE_CATALOG_RESOLVER_H
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#ifndef SQL_ENGINE_IN_MEMORY_CATALOG_H
2+
#define SQL_ENGINE_IN_MEMORY_CATALOG_H
3+
4+
#include "sql_engine/catalog.h"
5+
#include <string>
6+
#include <unordered_map>
7+
#include <vector>
8+
#include <initializer_list>
9+
10+
namespace sql_engine {
11+
12+
class InMemoryCatalog : public Catalog {
13+
public:
14+
// Add a table with columns.
15+
void add_table(const char* schema, const char* table,
16+
std::initializer_list<ColumnDef> columns);
17+
18+
// Remove a table.
19+
void drop_table(const char* schema, const char* table);
20+
21+
// Catalog interface
22+
const TableInfo* get_table(sql_parser::StringRef name) const override;
23+
const TableInfo* get_table(sql_parser::StringRef schema,
24+
sql_parser::StringRef table) const override;
25+
const ColumnInfo* get_column(const TableInfo* table,
26+
sql_parser::StringRef column_name) const override;
27+
28+
private:
29+
// Internal storage: owns strings and column arrays.
30+
struct TableData {
31+
std::string schema_str;
32+
std::string table_str;
33+
std::vector<std::string> column_names; // owns column name strings
34+
std::vector<ColumnInfo> columns;
35+
TableInfo info{};
36+
};
37+
38+
// Key: lowercase "schema.table" or just lowercase "table"
39+
std::unordered_map<std::string, TableData> tables_;
40+
41+
static std::string to_lower(const char* s, size_t len);
42+
static std::string make_key(const char* schema, const char* table);
43+
};
44+
45+
} // namespace sql_engine
46+
47+
#endif // SQL_ENGINE_IN_MEMORY_CATALOG_H
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
#include "sql_engine/in_memory_catalog.h"
2+
#include <algorithm>
3+
#include <cstring>
4+
5+
namespace sql_engine {
6+
7+
std::string InMemoryCatalog::to_lower(const char* s, size_t len) {
8+
std::string result(len, '\0');
9+
for (size_t i = 0; i < len; ++i) {
10+
char c = s[i];
11+
if (c >= 'A' && c <= 'Z') c += 32;
12+
result[i] = c;
13+
}
14+
return result;
15+
}
16+
17+
std::string InMemoryCatalog::make_key(const char* schema, const char* table) {
18+
std::string key;
19+
if (schema && schema[0] != '\0') {
20+
size_t slen = std::strlen(schema);
21+
key = to_lower(schema, slen);
22+
key += '.';
23+
}
24+
size_t tlen = std::strlen(table);
25+
key += to_lower(table, tlen);
26+
return key;
27+
}
28+
29+
void InMemoryCatalog::add_table(const char* schema, const char* table,
30+
std::initializer_list<ColumnDef> columns) {
31+
std::string key = make_key(schema, table);
32+
33+
TableData& td = tables_[key];
34+
td.schema_str = schema ? schema : "";
35+
td.table_str = table;
36+
td.column_names.clear();
37+
td.columns.clear();
38+
39+
uint16_t ordinal = 0;
40+
for (const auto& def : columns) {
41+
td.column_names.emplace_back(def.name);
42+
ColumnInfo ci{};
43+
// StringRef will point into the stored string -- set after push_back
44+
ci.type = def.type;
45+
ci.ordinal = ordinal++;
46+
ci.nullable = def.nullable;
47+
td.columns.push_back(ci);
48+
}
49+
50+
// Fix up StringRef pointers (must be done after all push_backs to avoid reallocation)
51+
for (size_t i = 0; i < td.columns.size(); ++i) {
52+
td.columns[i].name = sql_parser::StringRef{
53+
td.column_names[i].c_str(),
54+
static_cast<uint32_t>(td.column_names[i].size())
55+
};
56+
}
57+
58+
// Set up TableInfo
59+
td.info.schema_name = sql_parser::StringRef{
60+
td.schema_str.c_str(),
61+
static_cast<uint32_t>(td.schema_str.size())
62+
};
63+
td.info.table_name = sql_parser::StringRef{
64+
td.table_str.c_str(),
65+
static_cast<uint32_t>(td.table_str.size())
66+
};
67+
td.info.columns = td.columns.data();
68+
td.info.column_count = static_cast<uint16_t>(td.columns.size());
69+
70+
// Also register under unqualified name if schema is provided
71+
if (schema && schema[0] != '\0') {
72+
std::string unqualified = to_lower(table, std::strlen(table));
73+
// Only set unqualified key if it doesn't already exist or points to this same table
74+
if (tables_.find(unqualified) == tables_.end()) {
75+
// Store a reference entry: we don't duplicate, we just store another
76+
// entry pointing to the same data. But since we use value semantics,
77+
// we need to find via the qualified key. Instead, let get_table(name)
78+
// do a scan. Actually, for simplicity, store duplicate.
79+
// Better approach: unqualified lookup scans all entries.
80+
}
81+
}
82+
}
83+
84+
void InMemoryCatalog::drop_table(const char* schema, const char* table) {
85+
std::string key = make_key(schema, table);
86+
tables_.erase(key);
87+
}
88+
89+
const TableInfo* InMemoryCatalog::get_table(sql_parser::StringRef name) const {
90+
// Try exact (unqualified) lookup
91+
std::string lower = to_lower(name.ptr, name.len);
92+
auto it = tables_.find(lower);
93+
if (it != tables_.end()) return &it->second.info;
94+
95+
// Scan for matching table_name (for qualified entries)
96+
for (const auto& pair : tables_) {
97+
const TableData& td = pair.second;
98+
if (td.info.table_name.equals_ci(name.ptr, name.len)) {
99+
return &td.info;
100+
}
101+
}
102+
return nullptr;
103+
}
104+
105+
const TableInfo* InMemoryCatalog::get_table(sql_parser::StringRef schema,
106+
sql_parser::StringRef table) const {
107+
// Build qualified key
108+
std::string key = to_lower(schema.ptr, schema.len);
109+
key += '.';
110+
key += to_lower(table.ptr, table.len);
111+
auto it = tables_.find(key);
112+
if (it != tables_.end()) return &it->second.info;
113+
return nullptr;
114+
}
115+
116+
const ColumnInfo* InMemoryCatalog::get_column(const TableInfo* table,
117+
sql_parser::StringRef column_name) const {
118+
if (!table) return nullptr;
119+
for (uint16_t i = 0; i < table->column_count; ++i) {
120+
if (table->columns[i].name.equals_ci(column_name.ptr, column_name.len)) {
121+
return &table->columns[i];
122+
}
123+
}
124+
return nullptr;
125+
}
126+
127+
} // namespace sql_engine

0 commit comments

Comments
 (0)