Skip to content

Commit 2085b17

Browse files
committed
feat: add SQL engine type system — SqlType and Value
Add the foundational types for the sql_engine library: - SqlType struct with Kind enum (30 SQL types), precision/scale/flags, convenience constructors, and category query methods - Value tagged union with 14 tags, free-function constructors, is_null/is_numeric/is_string/is_temporal helpers, and to_double/to_int64 conversion methods - Comprehensive tests (24 new tests, 454 total)
1 parent a621a55 commit 2085b17

4 files changed

Lines changed: 513 additions & 1 deletion

File tree

Makefile.new

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ TEST_SRCS = $(TEST_DIR)/test_main.cpp \
3333
$(TEST_DIR)/test_delete.cpp \
3434
$(TEST_DIR)/test_compound.cpp \
3535
$(TEST_DIR)/test_digest.cpp \
36-
$(TEST_DIR)/test_misc_stmts.cpp
36+
$(TEST_DIR)/test_misc_stmts.cpp \
37+
$(TEST_DIR)/test_value.cpp
3738
TEST_OBJS = $(TEST_SRCS:.cpp=.o)
3839
TEST_TARGET = $(PROJECT_ROOT)/run_tests
3940

include/sql_engine/types.h

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#ifndef SQL_ENGINE_TYPES_H
2+
#define SQL_ENGINE_TYPES_H
3+
4+
#include <cstdint>
5+
6+
namespace sql_engine {
7+
8+
struct SqlType {
9+
enum Kind : uint8_t {
10+
// Numeric
11+
BOOLEAN,
12+
TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT,
13+
FLOAT, DOUBLE,
14+
DECIMAL,
15+
16+
// String
17+
CHAR, VARCHAR,
18+
TEXT, MEDIUMTEXT, LONGTEXT,
19+
BINARY, VARBINARY, BLOB,
20+
21+
// Temporal
22+
DATE,
23+
TIME,
24+
DATETIME,
25+
TIMESTAMP,
26+
INTERVAL,
27+
28+
// Structured
29+
JSON, JSONB,
30+
ENUM,
31+
ARRAY,
32+
33+
// Special
34+
NULL_TYPE,
35+
UNKNOWN
36+
};
37+
38+
Kind kind = UNKNOWN;
39+
uint16_t precision = 0;
40+
uint16_t scale = 0;
41+
bool is_unsigned = false;
42+
bool has_timezone = false;
43+
44+
// Convenience constructors
45+
static SqlType make_bool() { return {BOOLEAN}; }
46+
static SqlType make_tinyint(bool uns = false) { return {TINYINT, 0, 0, uns}; }
47+
static SqlType make_smallint(bool uns = false) { return {SMALLINT, 0, 0, uns}; }
48+
static SqlType make_int(bool uns = false) { return {INT, 0, 0, uns}; }
49+
static SqlType make_bigint(bool uns = false) { return {BIGINT, 0, 0, uns}; }
50+
static SqlType make_float() { return {FLOAT}; }
51+
static SqlType make_double() { return {DOUBLE}; }
52+
static SqlType make_decimal(uint16_t p, uint16_t s) { return {DECIMAL, p, s}; }
53+
static SqlType make_char(uint16_t len) { return {CHAR, len}; }
54+
static SqlType make_varchar(uint16_t len) { return {VARCHAR, len}; }
55+
static SqlType make_text() { return {TEXT}; }
56+
static SqlType make_blob() { return {BLOB}; }
57+
static SqlType make_date() { return {DATE}; }
58+
static SqlType make_time() { return {TIME}; }
59+
static SqlType make_datetime() { return {DATETIME}; }
60+
static SqlType make_timestamp(bool tz = false) { return {TIMESTAMP, 0, 0, false, tz}; }
61+
static SqlType make_json() { return {JSON}; }
62+
static SqlType make_null() { return {NULL_TYPE}; }
63+
64+
// Category queries
65+
bool is_numeric() const {
66+
return kind >= BOOLEAN && kind <= DECIMAL;
67+
}
68+
bool is_string() const {
69+
return kind >= CHAR && kind <= BLOB;
70+
}
71+
bool is_temporal() const {
72+
return kind >= DATE && kind <= INTERVAL;
73+
}
74+
bool is_structured() const {
75+
return kind >= JSON && kind <= ARRAY;
76+
}
77+
78+
bool operator==(const SqlType& o) const {
79+
return kind == o.kind && precision == o.precision &&
80+
scale == o.scale && is_unsigned == o.is_unsigned &&
81+
has_timezone == o.has_timezone;
82+
}
83+
bool operator!=(const SqlType& o) const { return !(*this == o); }
84+
};
85+
86+
} // namespace sql_engine
87+
88+
#endif // SQL_ENGINE_TYPES_H

include/sql_engine/value.h

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
#ifndef SQL_ENGINE_VALUE_H
2+
#define SQL_ENGINE_VALUE_H
3+
4+
#include "sql_engine/types.h"
5+
#include "sql_parser/common.h" // StringRef
6+
#include <cstdint>
7+
#include <type_traits>
8+
9+
namespace sql_engine {
10+
11+
using sql_parser::StringRef;
12+
13+
struct Value {
14+
enum Tag : uint8_t {
15+
TAG_NULL = 0,
16+
TAG_BOOL,
17+
TAG_INT64,
18+
TAG_UINT64,
19+
TAG_DOUBLE,
20+
TAG_DECIMAL, // stored as StringRef for now
21+
TAG_STRING,
22+
TAG_BYTES,
23+
TAG_DATE, // days since 1970-01-01 (int32)
24+
TAG_TIME, // microseconds since midnight (int64)
25+
TAG_DATETIME, // microseconds since epoch (int64)
26+
TAG_TIMESTAMP, // microseconds since epoch (int64)
27+
TAG_INTERVAL, // months + microseconds
28+
TAG_JSON, // stored as StringRef
29+
};
30+
31+
Tag tag = TAG_NULL;
32+
33+
union {
34+
bool bool_val;
35+
int64_t int_val;
36+
uint64_t uint_val;
37+
double double_val;
38+
StringRef str_val; // TAG_STRING, TAG_DECIMAL, TAG_BYTES, TAG_JSON
39+
int32_t date_val; // days since epoch
40+
int64_t time_val; // microseconds since midnight
41+
int64_t datetime_val; // microseconds since epoch
42+
int64_t timestamp_val; // microseconds since epoch
43+
struct { int32_t months; int64_t microseconds; } interval_val;
44+
};
45+
46+
bool is_null() const { return tag == TAG_NULL; }
47+
bool is_numeric() const { return tag >= TAG_BOOL && tag <= TAG_DECIMAL; }
48+
bool is_string() const { return tag == TAG_STRING; }
49+
bool is_temporal() const { return tag >= TAG_DATE && tag <= TAG_INTERVAL; }
50+
51+
// Convert numeric value to double (for arithmetic). Returns 0.0 for non-numeric.
52+
double to_double() const {
53+
switch (tag) {
54+
case TAG_BOOL: return bool_val ? 1.0 : 0.0;
55+
case TAG_INT64: return static_cast<double>(int_val);
56+
case TAG_UINT64: return static_cast<double>(uint_val);
57+
case TAG_DOUBLE: return double_val;
58+
default: return 0.0;
59+
}
60+
}
61+
62+
// Convert numeric value to int64 (for integer ops). Returns 0 for non-numeric.
63+
int64_t to_int64() const {
64+
switch (tag) {
65+
case TAG_BOOL: return bool_val ? 1 : 0;
66+
case TAG_INT64: return int_val;
67+
case TAG_UINT64: return static_cast<int64_t>(uint_val);
68+
case TAG_DOUBLE: return static_cast<int64_t>(double_val);
69+
default: return 0;
70+
}
71+
}
72+
};
73+
74+
// Value constructors -- free functions matching the spec
75+
inline Value value_null() {
76+
Value r{};
77+
r.tag = Value::TAG_NULL;
78+
return r;
79+
}
80+
81+
inline Value value_bool(bool v) {
82+
Value r{};
83+
r.tag = Value::TAG_BOOL;
84+
r.bool_val = v;
85+
return r;
86+
}
87+
88+
inline Value value_int(int64_t v) {
89+
Value r{};
90+
r.tag = Value::TAG_INT64;
91+
r.int_val = v;
92+
return r;
93+
}
94+
95+
inline Value value_uint(uint64_t v) {
96+
Value r{};
97+
r.tag = Value::TAG_UINT64;
98+
r.uint_val = v;
99+
return r;
100+
}
101+
102+
inline Value value_double(double v) {
103+
Value r{};
104+
r.tag = Value::TAG_DOUBLE;
105+
r.double_val = v;
106+
return r;
107+
}
108+
109+
inline Value value_decimal(StringRef s) {
110+
Value r{};
111+
r.tag = Value::TAG_DECIMAL;
112+
r.str_val = s;
113+
return r;
114+
}
115+
116+
inline Value value_string(StringRef s) {
117+
Value r{};
118+
r.tag = Value::TAG_STRING;
119+
r.str_val = s;
120+
return r;
121+
}
122+
123+
inline Value value_bytes(StringRef s) {
124+
Value r{};
125+
r.tag = Value::TAG_BYTES;
126+
r.str_val = s;
127+
return r;
128+
}
129+
130+
inline Value value_date(int32_t days) {
131+
Value r{};
132+
r.tag = Value::TAG_DATE;
133+
r.date_val = days;
134+
return r;
135+
}
136+
137+
inline Value value_time(int64_t us) {
138+
Value r{};
139+
r.tag = Value::TAG_TIME;
140+
r.time_val = us;
141+
return r;
142+
}
143+
144+
inline Value value_datetime(int64_t us) {
145+
Value r{};
146+
r.tag = Value::TAG_DATETIME;
147+
r.datetime_val = us;
148+
return r;
149+
}
150+
151+
inline Value value_timestamp(int64_t us) {
152+
Value r{};
153+
r.tag = Value::TAG_TIMESTAMP;
154+
r.timestamp_val = us;
155+
return r;
156+
}
157+
158+
inline Value value_interval(int32_t months, int64_t us) {
159+
Value r{};
160+
r.tag = Value::TAG_INTERVAL;
161+
r.interval_val = {months, us};
162+
return r;
163+
}
164+
165+
inline Value value_json(StringRef s) {
166+
Value r{};
167+
r.tag = Value::TAG_JSON;
168+
r.str_val = s;
169+
return r;
170+
}
171+
172+
} // namespace sql_engine
173+
174+
#endif // SQL_ENGINE_VALUE_H

0 commit comments

Comments
 (0)