27 auto n = as<const Numeric>(ty);
30 case Numeric::N_Decimal:
32 case Numeric::N_Float:
33 return n->precision == 32 ?
"_f" :
"_d";
51 const std::vector<Schema> &schemas,
52 const std::vector<std::size_t> &tuple_ids)
61 static std::unordered_map<std::string, std::regex>
regexes_;
64 std::pair<std::size_t, std::size_t>
66 for (std::size_t schema_idx = 0; schema_idx !=
schemas_.size(); ++schema_idx) {
70 return {
tuple_ids_[schema_idx], std::distance(S.cbegin(), it) };
75 using ConstASTExprVisitor::operator();
77 void operator()(Const<ast::Designator> &e)
override;
78 void operator()(Const<ast::Constant> &e)
override;
79 void operator()(Const<ast::FnApplicationExpr> &e)
override;
80 void operator()(Const<ast::UnaryExpr> &e)
override;
81 void operator()(Const<ast::BinaryExpr> &e)
override;
82 void operator()(Const<ast::QueryExpr> &e)
override;
89 auto [tuple_id, attr_id] =
find_id({e.table_name.text, e.attr_name.text.assert_not_none()});
103 auto &fn = e.get_function();
113 case Function::FN_ISNULL:
120 case Function::FN_INT: {
123 auto ty = e.args[0]->type();
126 else if (ty->is_double())
128 else if (ty->is_decimal()) {
130 }
else if (ty->is_boolean()) {
139 case Function::FN_COUNT:
140 case Function::FN_MIN:
141 case Function::FN_MAX:
142 case Function::FN_SUM:
143 case Function::FN_AVG: {
144 std::ostringstream oss;
146 auto name = C.pool(oss.str().c_str());
147 auto [tuple_id, attr_id] =
find_id({name});
157 auto ty = e.expr->type();
159 switch (e.op().type) {
168 auto n = as<const Numeric>(ty);
171 case Numeric::N_Decimal:
175 case Numeric::N_Float:
176 if (n->precision == 32)
185 if (ty->is_integral())
187 else if (ty->is_boolean())
194 M_insist(ty->is_boolean(),
"illegal type");
202 auto ty = as<const PrimitiveType>(e.type());
203 auto ty_lhs = as<const PrimitiveType>(e.lhs->type());
204 auto ty_rhs = as<const PrimitiveType>(e.rhs->type());
205 auto tystr_to =
tystr(ty);
209 std::string tystr_to =
tystr(to_ty);
210 std::string tystr_from =
tystr(from_ty);
212 if (tystr_from != tystr_to) {
213 std::string opstr =
"Cast" + tystr_to + tystr_from;
221 auto n_from = as<const Numeric>(from_ty);
222 auto n_to = as<const Numeric>(to_ty);
223 if (n_from->scale < n_to->scale) {
224 M_insist(n_to->is_decimal(),
"only decimals have a scale");
226 const uint32_t delta = n_to->scale - n_from->scale;
227 const int64_t factor = powi<int64_t>(10, delta);
228 switch (n_from->kind) {
229 case Numeric::N_Float:
230 if (n_from->precision == 32) {
239 case Numeric::N_Decimal:
245 }
else if (n_from->scale > n_to->scale) {
246 M_insist(n_from->is_decimal(),
"only decimals have a scale");
248 const uint32_t delta = n_from->scale - n_to->scale;
249 const int64_t factor = powi<int64_t>(10, delta);
250 switch (n_from->kind) {
251 case Numeric::N_Float:
252 if (n_from->precision == 32) {
261 case Numeric::N_Decimal:
272 auto load_numeric = [&](
auto val,
const Numeric *n) {
275 case Numeric::N_Decimal:
278 case Numeric::N_Float:
279 if (n->precision == 32)
288 switch (e.op().type) {
292 case TK_PLUS: opname =
"Add";
break;
293 case TK_MINUS: opname =
"Sub";
break;
294 case TK_ASTERISK: opname =
"Mul";
break;
295 case TK_SLASH: opname =
"Div";
break;
296 case TK_PERCENT: opname =
"Mod";
break;
299 case TK_DOTDOT: opname =
"Cat";
break;
302 case TK_LESS: opname =
"LT";
break;
303 case TK_GREATER: opname =
"GT";
break;
304 case TK_LESS_EQUAL: opname =
"LE";
break;
305 case TK_GREATER_EQUAL: opname =
"GE";
break;
306 case TK_EQUAL: opname =
"Eq";
break;
307 case TK_BANG_EQUAL: opname =
"NE";
break;
308 case TK_Like: opname =
"Like";
break;
311 case TK_And: opname =
"And";
break;
312 case TK_Or: opname =
"Or";
break;
315 switch (e.op().type) {
323 emit_cast(ty_lhs, ty);
327 emit_cast(ty_rhs, ty);
329 std::string opstr = e.op().type == TK_PLUS ?
"Add" :
"Sub";
337 auto n_lhs = as<const Numeric>(ty_lhs);
338 auto n_rhs = as<const Numeric>(ty_rhs);
339 auto n_res = as<const Numeric>(ty);
340 uint32_t the_scale = 0;
343 if (n_lhs->is_floating_point()) {
345 the_scale += n_res->scale;
347 the_scale += n_lhs->scale;
349 emit_cast(n_lhs, n_res);
352 if (n_rhs->is_floating_point()) {
354 the_scale += n_res->scale;
356 the_scale += n_rhs->scale;
358 emit_cast(n_rhs, n_res);
360 std::string opstr =
"Mul";
366 the_scale -= n_res->scale;
368 if (the_scale != 0) {
370 const int64_t factor = powi<int64_t>(10, the_scale);
371 load_numeric(factor, n_res);
393 auto n_lhs = as<const Numeric>(ty_lhs);
394 auto n_rhs = as<const Numeric>(ty_rhs);
395 auto n_res = as<const Numeric>(ty);
396 int32_t the_scale = 0;
399 if (n_lhs->is_floating_point()) {
401 the_scale += n_res->scale;
403 the_scale += n_lhs->scale;
405 emit_cast(n_lhs, n_res);
407 if (n_rhs->is_floating_point())
408 the_scale -= n_res->scale;
410 the_scale -= n_rhs->scale;
412 if (the_scale < int32_t(n_res->scale)) {
413 const int64_t factor =
powi(10L, n_res->scale - the_scale);
414 load_numeric(factor, n_res);
419 if (n_rhs->is_floating_point())
421 emit_cast(n_rhs, n_res);
423 std::string opstr =
"Div";
428 if (the_scale > int32_t(n_res->scale)) {
429 const int64_t factor =
powi(10L, the_scale - n_res->scale);
430 load_numeric(factor, n_res);
454 case TK_GREATER_EQUAL:
457 if (ty_lhs->is_numeric()) {
459 auto n_lhs = as<const Numeric>(ty_lhs);
460 auto n_rhs = as<const Numeric>(ty_rhs);
465 emit_cast(n_lhs, n_res);
469 emit_cast(n_rhs, n_res);
471 std::string opstr = opname +
tystr(n_res);
477 std::string opstr = opname +
tystr(ty_lhs);
484 if (
auto rhs = cast<const ast::Constant>(e.rhs.get())) {
486 auto pattern =
interpret(*rhs->tok.text);
518 auto [tuple_id, attr_id] =
find_id({e.alias(), C.
pool(
"$res")});
528#define M_OPCODE(CODE, ...) { #CODE, StackMachine::Opcode:: CODE },
529#include "tables/Opcodes.tbl"
534 : in_schema(in_schema)
541 : in_schema(in_schema)
553 emit_Ld_Tup(tuple_id, idx);
556 std::vector<std::size_t> tuple_ids({tuple_id});
567 emit_Ld_Tup(tuple_id, idx);
569 std::vector<Schema> svec({schema});
570 std::vector<std::size_t> tuple_ids({tuple_id});
576 std::vector<Schema> &schemas,
577 std::vector<std::size_t> &tuple_ids)
585 for (
auto clause_it = cnf.cbegin(); clause_it != cnf.cend(); ++clause_it) {
586 auto &C = *clause_it;
587 for (
auto pred_it = C.cbegin(); pred_it != C.cend(); ++pred_it) {
591 ops.push_back(StackMachine::Opcode::Not_b);
592 if (pred_it != C.cbegin())
593 ops.push_back(StackMachine::Opcode::Or_b);
595 if (clause_it != cnf.cbegin())
596 ops.push_back(StackMachine::Opcode::And_b);
601 std::vector<Schema> &schemas,
602 std::vector<std::size_t> &tuple_ids)
605 for (
auto clause_it = cnf.cbegin(); clause_it != cnf.cend(); ++clause_it) {
606 auto &C = *clause_it;
607 for (
auto pred_it = C.cbegin(); pred_it != C.cend(); ++pred_it) {
609 emit(*P, schemas, tuple_ids);
611 ops.push_back(StackMachine::Opcode::Not_b);
612 if (pred_it != C.cbegin())
613 ops.push_back(StackMachine::Opcode::Or_b);
615 if (clause_it != cnf.cbegin())
616 ops.push_back(StackMachine::Opcode::And_b);
624 if (
auto n = cast<const Numeric>(ty)) {
627 case Numeric::N_Decimal: {
630 case 8: emit_Ld_i8();
break;
631 case 16: emit_Ld_i16();
break;
632 case 32: emit_Ld_i32();
break;
633 case 64: emit_Ld_i64();
break;
638 case Numeric::N_Float: {
646 }
else if (
auto cs = cast<const CharacterSequence>(ty)) {
649 }
else if (
auto d = cast<const Date>(ty)) {
651 }
else if (
auto dt = cast<const DateTime>(ty)) {
662 if (
auto n = cast<const Numeric>(ty)) {
665 case Numeric::N_Decimal: {
668 case 8: emit_St_i8();
break;
669 case 16: emit_St_i16();
break;
670 case 32: emit_St_i32();
break;
671 case 64: emit_St_i64();
break;
676 case Numeric::N_Float: {
684 }
else if (
auto cs = cast<const CharacterSequence>(ty)) {
687 }
else if (
auto d = cast<const Date>(ty)) {
689 }
else if (
auto dt = cast<const DateTime>(ty)) {
699 emit_St_Tup_Null(tuple_id, index);
700 }
else if (
auto cs = cast<const CharacterSequence>(ty)) {
702 emit_St_Tup_s(tuple_id, index);
704 std::ostringstream oss;
705 oss <<
"St_Tup" <<
tystr(as<const PrimitiveType>(ty));
717 emit_Print_i(ostream_index);
725 std::ostringstream oss;
726 oss <<
"Print" <<
tystr(as<const PrimitiveType>(ty));
735 auto to = as<const PrimitiveType>(to_ty);
736 auto from = as<const PrimitiveType>(from_ty);
737 if (from->as_vectorial() == to->as_vectorial())
return;
739 if (
auto n_from = cast<const Numeric>(from)) {
740 auto n_to = as<const Numeric>(to);
742 switch (n_from->kind) {
744 switch (n_to->kind) {
749 case Numeric::N_Decimal:
754 case Numeric::N_Float:
755 if (n_to->size() == 32)
763 case Numeric::N_Float:
764 if (n_from->size() == 32) {
765 switch (n_to->kind) {
770 case Numeric::N_Decimal:
776 case Numeric::N_Float:
777 M_insist(n_to->size() == 64,
"float to float");
782 switch (n_to->kind) {
787 case Numeric::N_Decimal:
793 case Numeric::N_Float:
794 M_insist(n_to->size() == 32,
"double to double");
801 case Numeric::N_Decimal:
802 switch (n_to->kind) {
808 case Numeric::N_Decimal: {
809 if (n_to->scale != n_from->scale) {
810 if (n_to->scale > n_from->scale) {
821 case Numeric::N_Float:
822 if (n_to->size() == 32) {
835 }
else if (
auto cs_from = cast<const CharacterSequence>(from_ty)) {
838 }
else if (
auto b_from = cast<const Boolean>(from_ty)) {
839 auto n_to = as<const Numeric>(to);
842 switch (n_to->kind) {
847 case Numeric::N_Float:
848 case Numeric::N_Decimal:
858 static const void *labels[] = {
859#define M_OPCODE(CODE, ...) && CODE,
860#include "tables/Opcodes.tbl"
873#define NEXT goto *labels[std::size_t(*op_++)]
875#define PUSH(VAL, NUL) { \
876 M_insist(top_ < required_stack_size(), "index out of bounds"); \
877 values_[top_] = (VAL); \
878 null_bits_[top_] = (NUL); \
882#define TOP_IS_NULL (null_bits_[top_ - 1UL])
883#define TOP (values_[top_ - 1UL])
894 if (
TOP.as_i() == 0)
goto Stop;
900 if (
TOP.as_i() != 0)
goto Stop;
906 if (not
TOP.as_b())
goto Stop;
912 if (
TOP.as_b())
goto Stop;
940 std::size_t idx = std::size_t(*
op_++);
948 std::size_t idx =
static_cast<std::size_t
>(*
op_++);
950#ifdef M_ENABLE_SANITY_FIELDS
951 M_insist(
context_[idx].type ==
TOP.type,
"update must not change the type of a context entry");
963 std::size_t tuple_id = std::size_t(*
op_++);
964 std::size_t index = std::size_t(*
op_++);
965 auto &t = *tuples[tuple_id];
966 PUSH(t[index], t.is_null(index));
971 std::size_t tuple_id = std::size_t(*
op_++);
972 std::size_t index = std::size_t(*
op_++);
973 auto &t = *tuples[tuple_id];
982 std::size_t tuple_id = std::size_t(*
op_++);
983 std::size_t index = std::size_t(*
op_++);
984 auto &t = *tuples[tuple_id];
990 std::size_t tuple_id = std::size_t(*
op_++);
991 std::size_t index = std::size_t(*
op_++);
992 std::size_t length =
TOP.as_i();
994 auto &t = *tuples[tuple_id];
999 char *dst =
reinterpret_cast<char*
>(t[index].as_p());
1000 char *src =
reinterpret_cast<char*
>(
TOP.as_p());
1001 strncpy(dst,
reinterpret_cast<char*
>(src), length);
1013 std::size_t index = std::size_t(*
op_++);
1014 unsigned char chr = (
unsigned char)(*
op_++);
1015 std::ostream &out = *
reinterpret_cast<std::ostream*
>(
context_[index].as_p());
1022 std::size_t index = std::size_t(*
op_++);
1023 std::ostream &out = *
reinterpret_cast<std::ostream*
>(
context_[index].as_p());
1033 std::size_t index = std::size_t(*
op_++);
1034 std::ostream &out = *
reinterpret_cast<std::ostream*
>(
context_[index].as_p());
1038 const auto old_precision = out.precision(std::numeric_limits<float>::max_digits10 - 1);
1040 out.precision(old_precision);
1047 std::size_t index = std::size_t(*
op_++);
1048 std::ostream &out = *
reinterpret_cast<std::ostream*
>(
context_[index].as_p());
1052 const auto old_precision = out.precision(std::numeric_limits<double>::max_digits10 - 1);
1054 out.precision(old_precision);
1061 std::size_t index = std::size_t(*
op_++);
1062 std::ostream &out = *
reinterpret_cast<std::ostream*
>(
context_[index].as_p());
1066 const char *str =
reinterpret_cast<char*
>(
TOP.as_p());
1067 out <<
'"' << str <<
'"';
1074 std::size_t index = std::size_t(*
op_++);
1075 std::ostream &out = *
reinterpret_cast<std::ostream*
>(
context_[index].as_p());
1079 out << (
TOP.as_b() ?
"TRUE" :
"FALSE");
1084 std::size_t index = std::size_t(*
op_++);
1085 std::ostream &out = *
reinterpret_cast<std::ostream*
>(
context_[index].as_p());
1089 const int32_t date =
TOP.as_i();
1090 const auto oldfill = out.fill(
'0');
1091 const auto oldfmt = out.flags();
1092 out << std::internal
1093 << std::setw(date >> 9 > 0 ? 4 : 5) << (date >> 9) <<
'-'
1094 << std::setw(2) << ((date >> 5) & 0xF) <<
'-'
1095 << std::setw(2) << (date & 0x1F);
1103 std::size_t index = std::size_t(*
op_++);
1104 std::ostream &out = *
reinterpret_cast<std::ostream*
>(
context_[index].as_p());
1108 const time_t time =
TOP.as_i();
1110 gmtime_r(&time, &tm);
1123#define LOAD(TO_TYPE, FROM_TYPE) { \
1124 M_insist(top_ >= 1); \
1125 const void *ptr = TOP.as_p(); \
1126 TOP = (TO_TYPE)(*reinterpret_cast<const FROM_TYPE*>(ptr)); \
1130Ld_i8:
LOAD(int64_t, int8_t);
1131Ld_i16:
LOAD(int64_t, int16_t);
1132Ld_i32:
LOAD(int64_t, int32_t);
1133Ld_i64:
LOAD(int64_t, int64_t);
1134Ld_f:
LOAD(
float,
float);
1135Ld_d:
LOAD(
double,
double);
1139 uint64_t length =
TOP.as_i();
1141 void *ptr =
TOP.as_p();
1142 strncpy(
reinterpret_cast<char*
>(p_mem),
reinterpret_cast<char*
>(ptr), length);
1145 p_mem += length + 1;
1151 uint64_t mask = uint64_t(*
op_++);
1152 void *ptr =
TOP.as_p();
1153 TOP = bool(*
reinterpret_cast<uint8_t*
>(ptr) & mask);
1161#define STORE(TO_TYPE, FROM_TYPE) { \
1162 M_insist(top_ >= 2); \
1163 if (TOP_IS_NULL) { POP(); POP(); NEXT; } \
1164 TO_TYPE val = TOP.as<FROM_TYPE>(); \
1166 void *ptr = TOP.as_p(); \
1167 *reinterpret_cast<TO_TYPE*>(ptr) = val; \
1172St_i8:
STORE(int8_t, int64_t);
1173St_i16:
STORE(int16_t, int64_t);
1174St_i32:
STORE(int32_t, int64_t);
1175St_i64:
STORE(int64_t, int64_t);
1176St_f:
STORE(
float,
float);
1177St_d:
STORE(
double,
double);
1181 uint64_t length =
TOP.as_i();
1185 char *str =
reinterpret_cast<char*
>(
TOP.as_p());
1187 char *dst =
reinterpret_cast<char*
>(
TOP.as_p());
1189 strncpy(dst, str, length);
1195 uint64_t bit_offset = uint64_t(*
op_++);
1198 bool val =
TOP.as_b();
1200 void *ptr =
TOP.as_p();
1201 setbit(
reinterpret_cast<uint8_t*
>(ptr), val, bit_offset);
1213#define UNARY(OP, TYPE) { \
1214 M_insist(top_ >= 1); \
1215 TYPE val = TOP.as<TYPE>(); \
1220#define BINARY(OP, TYPE) { \
1221 M_insist(top_ >= 2); \
1222 TYPE rhs = TOP.as<TYPE>(); \
1223 bool is_rhs_null = TOP_IS_NULL; \
1225 TYPE lhs = TOP.as<TYPE>(); \
1226 TOP = OP(lhs, rhs); \
1227 TOP_IS_NULL = TOP_IS_NULL or is_rhs_null; \
1232Inc:
UNARY(++, int64_t);
1235Dec:
UNARY(--, int64_t);
1238Minus_i:
UNARY(-, int64_t);
1239Minus_f:
UNARY(-,
float);
1240Minus_d:
UNARY(-,
double);
1243Add_i:
BINARY(std::plus{}, int64_t);
1244Add_f:
BINARY(std::plus{}, float);
1245Add_d:
BINARY(std::plus{}, double);
1248 void *rhs =
TOP.as_p();
1250 const uint64_t lhs =
TOP.as<int64_t>();
1252 TOP = lhs +
reinterpret_cast<uint8_t*
>(rhs);
1258Sub_i:
BINARY(std::minus{}, int64_t);
1259Sub_f:
BINARY(std::minus{}, float);
1260Sub_d:
BINARY(std::minus{}, double);
1263Mul_i:
BINARY(std::multiplies{}, int64_t);
1264Mul_f:
BINARY(std::multiplies{}, float);
1265Mul_d:
BINARY(std::multiplies{}, double);
1268Div_i:
BINARY(std::divides{}, int64_t);
1269Div_f:
BINARY(std::divides{}, float);
1270Div_d:
BINARY(std::divides{}, double);
1273Mod_i:
BINARY(std::modulus{}, int64_t);
1294 char *dest =
reinterpret_cast<char*
>(p_mem);
1297 for (
auto src = lhs.
as<
char*>(); *src; ++src, ++dest)
1300 for (
auto src = rhs.
as<
char*>(); *src; ++src, ++dest)
1303 p_mem =
reinterpret_cast<uint8_t*
>(dest);
1313Neg_i:
UNARY(~, int64_t);
1316And_i:
BINARY(std::bit_and{}, int64_t);
1319Or_i:
BINARY(std::bit_or{}, int64_t);
1322Xor_i:
BINARY(std::bit_xor{}, int64_t);
1327 uint64_t count =
TOP.as<int64_t>();
1329 uint64_t val =
TOP.as<int64_t>();
1330 TOP = uint64_t(val << count);
1337 std::size_t count = std::size_t(*
op_++);
1338 uint64_t val =
TOP.as<int64_t>();
1339 TOP = uint64_t(val << count);
1346 std::size_t count = std::size_t(*
op_++);
1347 int64_t val =
TOP.as<int64_t>();
1348 TOP = int64_t(val >> count);
1358Not_b:
UNARY(not,
bool);
1363 bool rhs =
TOP.as<
bool>();
1366 bool lhs =
TOP.as<
bool>();
1369 TOP_IS_NULL = (lhs or is_lhs_null)
and (rhs or is_rhs_null)
and (is_lhs_null or is_rhs_null);
1376 bool rhs =
TOP.as<
bool>();
1379 bool lhs =
TOP.as<
bool>();
1382 TOP_IS_NULL = (not lhs or is_lhs_null)
and (not rhs or is_rhs_null)
and (is_lhs_null or is_rhs_null);
1393 uint64_t val =
TOP.as<int64_t>();
1400 uint64_t val =
TOP.as<int64_t>();
1405Eq_i:
BINARY(std::equal_to{}, int64_t);
1406Eq_f:
BINARY(std::equal_to{}, float);
1407Eq_d:
BINARY(std::equal_to{}, double);
1408Eq_b:
BINARY(std::equal_to{}, bool);
1411NE_i:
BINARY(std::not_equal_to{}, int64_t);
1412NE_f:
BINARY(std::not_equal_to{}, float);
1413NE_d:
BINARY(std::not_equal_to{}, double);
1414NE_b:
BINARY(std::not_equal_to{}, bool);
1417LT_i:
BINARY(std::less{}, int64_t);
1418LT_f:
BINARY(std::less{}, float);
1419LT_d:
BINARY(std::less{}, double);
1420LT_s:
BINARY(0 > strcmp,
char*)
1422GT_i:
BINARY(std::greater{}, int64_t);
1423GT_f:
BINARY(std::greater{}, float);
1424GT_d:
BINARY(std::greater{}, double);
1425GT_s:
BINARY(0 < strcmp,
char*);
1427LE_i:
BINARY(std::less_equal{}, int64_t);
1428LE_f:
BINARY(std::less_equal{}, float);
1429LE_d:
BINARY(std::less_equal{}, double);
1430LE_s:
BINARY(0 >= strcmp,
char*);
1432GE_i:
BINARY(std::greater_equal{}, int64_t);
1433GE_f:
BINARY(std::greater_equal{}, float);
1434GE_d:
BINARY(std::greater_equal{}, double);
1435GE_s:
BINARY(0 <= strcmp,
char*);
1437#define CMP(TYPE) { \
1438 M_insist(top_ >= 2); \
1439 TYPE rhs = TOP.as<TYPE>(); \
1440 bool is_rhs_null = TOP_IS_NULL; \
1442 TYPE lhs = TOP.as<TYPE>(); \
1443 bool is_lhs_null = TOP_IS_NULL; \
1444 TOP = int64_t(lhs >= rhs) - int64_t(lhs <= rhs); \
1445 TOP_IS_NULL = is_lhs_null or is_rhs_null; \
1453Cmp_s:
BINARY(strcmp,
char*);
1459 std::regex *re =
TOP.as<std::regex*>();
1462 char *str =
TOP.as<
char*>();
1463 TOP = std::regex_match(str, *re);
1474 char *pattern =
TOP.as<
char*>();
1477 char *str =
TOP.as<
char*>();
1525Cast_i_f:
UNARY((int64_t),
float);
1526Cast_i_d:
UNARY((int64_t),
double);
1527Cast_i_b:
UNARY((int64_t),
bool);
1530Cast_f_i:
UNARY((
float), int64_t);
1531Cast_f_d:
UNARY((
float),
double);
1534Cast_d_i:
UNARY((
double), int64_t);
1535Cast_d_f:
UNARY((
double),
float);
1550 out <<
"StackMachine\n Context: [";
1552 if (it !=
context_.cbegin()) out <<
", ";
1557 <<
"\n Output Schema: {[";
1563 <<
"\n Opcode Sequence:\n";
1564 const std::size_t current_op =
op_ -
ops.begin();
1565 for (std::size_t i = 0; i !=
ops.size(); ++i) {
1567 if (i == current_op)
1571 out <<
"[0x" << std::hex << std::setfill(
'0') << std::setw(4) << i << std::dec <<
"]: "
1575 case Opcode::St_Tup_s:
1577 out << ' ' << static_cast<int64_t>(
ops[i]);
1581 case Opcode::Ld_Tup:
1582 case Opcode::St_Tup_Null:
1583 case Opcode::St_Tup_i:
1584 case Opcode::St_Tup_f:
1585 case Opcode::St_Tup_d:
1586 case Opcode::St_Tup_b:
1589 out << ' ' << static_cast<int64_t>(
ops[i]);
1593 case Opcode::Ld_Ctx:
1594 case Opcode::Upd_Ctx:
1595 case Opcode::Print_i:
1596 case Opcode::Print_f:
1597 case Opcode::Print_d:
1598 case Opcode::Print_s:
1599 case Opcode::Print_b:
1605 out << ' ' << static_cast<int64_t>(
ops[i]);
1613 for (std::size_t i =
top_; i --> 0; ) {
1617 out <<
" " <<
values_[i] <<
'\n';
#define LOAD(TO_TYPE, FROM_TYPE)
const char * tystr(const PrimitiveType *ty)
Return the type suffix for the given PrimitiveType ty.
#define STORE(TO_TYPE, FROM_TYPE)
#define M_unreachable(MSG)
T M_EXPORT powi(const T base, const U exp)
Power function for integral types.
const Numeric * arithmetic_join(const Numeric *lhs, const Numeric *rhs)
bool streq(const char *first, const char *second)
std::regex pattern_to_regex(const char *pattern, const bool optimize=false, const char escape_char='\\')
Transforms a SQL-style LIKE pattern into a std::regex.
bool M_EXPORT like(const std::string &str, const std::string &pattern, const char escape_char='\\')
Compares a SQL-style LIKE pattern with the given std::string.
std::string interpret(const std::string &str, char esc='\\', char quote='"')
void M_EXPORT setbit(T *bytes, bool value, uint32_t n)
The catalog contains all Databases and keeps track of all meta information of the database system.
ThreadSafePooledString pool(const char *str) const
Creates an internalized copy of the string str by adding it to the internal StringPool.
static Catalog & Get()
Return a reference to the single Catalog instance.
The numeric type represents integer and floating-point types of different precision and scale.
PrimitiveTypes represent Types of values.
An Identifier is composed of a name and an optional prefix.
A Schema represents a sequence of identifiers, optionally with a prefix, and their associated types.
std::size_t num_entries() const
Returns the number of entries in this Schema.
iterator find(const Identifier &id)
Returns an iterator to the entry with the given Identifier id, or end() if no such entry exists.
void operator()(Const< ast::ErrorExpr > &) override
StackMachineBuilder(StackMachine &stack_machine, const ast::Expr &expr, const std::vector< Schema > &schemas, const std::vector< std::size_t > &tuple_ids)
std::pair< std::size_t, std::size_t > find_id(const Schema::Identifier &id) const
Returns a pair of (tuple_id, attr_id).
const std::vector< Schema > & schemas_
StackMachine & stack_machine_
const std::vector< std::size_t > & tuple_ids_
static std::unordered_map< std::string, std::regex > regexes_
regexes built from patterns in LIKE expressions
A stack machine that evaluates an expression.
Schema in_schema
schema of the input tuple
void emit_Print(std::size_t ostream_index, const Type *ty)
Emit a Print_X instruction based on Type ty, e.g. Print_i for integral Types.
std::size_t add_and_emit_load(Value val)
Adds the Value val to the context and emits a load instruction to load this value to the top of the s...
std::vector< Value > context_
the context of the stack machine, e.g. constants or global variables
bool * null_bits_
array of NULL bits used as a stack
static const std::unordered_map< std::string, Opcode > STR_TO_OPCODE
static constexpr const char * OPCODE_TO_STR[]
StackMachine()
Create a StackMachine that does not accept input.
void emit_Ld(const Type *ty)
Emit a Ld_X instruction based on Type ty, e.g. Ld_i32 for 4 byte integral types.
Value * values_
array of values used as a stack
std::size_t top_
the top of the stack
void emit_St(const Type *ty)
Emit a St_X instruction based on Type ty, e.g. St_i32 for 4 byte integral types.
std::vector< Opcode > ops
the sequence of operations to perform
decltype(ops) ::const_iterator op_
the next operation to execute
std::vector< const Type * > out_schema
schema of the output tuple
void operator()(Tuple **tuples) const
Evaluate this StackMachine given the Tuples referenced by tuples.
void emit_St_Tup(std::size_t tuple_id, std::size_t index, const Type *ty)
Emit a St_Tup_X instruction based on Type ty, e.g. St_Tup_i for integral Types.
uint8_t memory_[SIZE_OF_MEMORY]
memory usable by the stack machine, e.g. to work on BLOBs
void emit(const ast::Expr &expr, std::size_t tuple_id=0)
Emit operations evaluating the Expr expr.
std::size_t required_stack_size() const
Returns the required size of the stack to evaluate the opcode sequence.
friend struct StackMachineBuilder
void emit_Cast(const Type *to_ty, const Type *from_ty)
Emit opcodes to convert a value of Type from_ty to Type to_ty.
void null(std::size_t idx)
Sets the Value at index idx to NULL.
void set(std::size_t idx, Value val)
Assigns the Value val to this Tuple at index idx and clears the respective NULL bit.
This class represents types in the SQL type system.
bool is_date_time() const
bool is_character_sequence() const
bool is_numeric() const
Returns true iff this Type is a Numeric type.
This class holds a SQL attribute value.
auto & as_b()
Returns a reference to the value interpreted as of type bool.
std::conditional_t< std::is_pointer_v< T >, T, T & > as()
Returns a reference to the value interpreted as of type T.
A CNF represents a conjunction of cnf::Clauses.