summaryrefslogtreecommitdiff
path: root/lib/row.cpp
blob: d59cdbade3b6c5d8f2816ce0fd92ac0a06b7f164 (plain)
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
#include "row.h"
#include <stdexcept>
#include <string>

namespace MyGrate {
	Row::Row(const st_mariadb_rpl_rows_event & r, const st_mariadb_rpl_table_map_event & t) : row {r}, tm {t} { }

	void
	Row::forEachField(const std::function<void(MySQL::FieldValue)> & cb)
	{
		MyGrate::RawDataReader md {tm.metadata};
		MyGrate::RawDataReader data {row.row_data, row.row_data_size};
		const size_t flagBytes {(tm.column_count + 7) / 8};
		MyGrate::BitSet nullFlags {data.viewValue<std::span<const std::byte>>(flagBytes)};
		MyGrate::BitSet columnFlags {{reinterpret_cast<const std::byte *>(row.column_bitmap), flagBytes}};
		auto nullIter {nullFlags.begin()};
		auto colIter {columnFlags.begin()};
		for (auto c {0U}; c < tm.column_count; c++) {
			if (*colIter) {
				const enum_field_types type {(enum_field_types)(unsigned char)tm.column_types.str[c]};
				const auto null {*nullIter};
				if (null) {
					switch (type) {
						case MYSQL_TYPE_BIT:
						case MYSQL_TYPE_ENUM:
						case MYSQL_TYPE_SET:
						case MYSQL_TYPE_NEWDECIMAL:
						case MYSQL_TYPE_DECIMAL:
						case MYSQL_TYPE_VARCHAR:
						case MYSQL_TYPE_VAR_STRING:
						case MYSQL_TYPE_STRING:
							md.discard(2);
							break;
						case MYSQL_TYPE_TINY_BLOB:
						case MYSQL_TYPE_MEDIUM_BLOB:
						case MYSQL_TYPE_LONG_BLOB:
						case MYSQL_TYPE_BLOB:
						case MYSQL_TYPE_FLOAT:
						case MYSQL_TYPE_DOUBLE:
						case MYSQL_TYPE_TIMESTAMP2:
						case MYSQL_TYPE_DATETIME2:
						case MYSQL_TYPE_TIME2:
							md.discard(1);
							break;
						default:;
					}
					cb(nullptr);
				}
				else {
					switch (type) {
#define TYPE_CALLBACK(T) \
	case T: \
		cb(MySQL::Type<T>::read(md, data)); \
		break
						TYPE_CALLBACK(MYSQL_TYPE_DECIMAL);
						TYPE_CALLBACK(MYSQL_TYPE_TINY);
						TYPE_CALLBACK(MYSQL_TYPE_SHORT);
						TYPE_CALLBACK(MYSQL_TYPE_LONG);
						TYPE_CALLBACK(MYSQL_TYPE_FLOAT);
						TYPE_CALLBACK(MYSQL_TYPE_DOUBLE);
						TYPE_CALLBACK(MYSQL_TYPE_NULL);
						TYPE_CALLBACK(MYSQL_TYPE_TIMESTAMP);
						TYPE_CALLBACK(MYSQL_TYPE_LONGLONG);
						TYPE_CALLBACK(MYSQL_TYPE_INT24);
						TYPE_CALLBACK(MYSQL_TYPE_DATE);
						TYPE_CALLBACK(MYSQL_TYPE_TIME);
						TYPE_CALLBACK(MYSQL_TYPE_DATETIME);
						TYPE_CALLBACK(MYSQL_TYPE_YEAR);
						TYPE_CALLBACK(MYSQL_TYPE_NEWDATE);
						TYPE_CALLBACK(MYSQL_TYPE_BIT);
						TYPE_CALLBACK(MYSQL_TYPE_TIMESTAMP2);
						TYPE_CALLBACK(MYSQL_TYPE_TIME2);
						TYPE_CALLBACK(MYSQL_TYPE_JSON);
						TYPE_CALLBACK(MYSQL_TYPE_NEWDECIMAL);
						TYPE_CALLBACK(MYSQL_TYPE_ENUM);
						TYPE_CALLBACK(MYSQL_TYPE_SET);
						TYPE_CALLBACK(MYSQL_TYPE_TINY_BLOB);
						TYPE_CALLBACK(MYSQL_TYPE_MEDIUM_BLOB);
						TYPE_CALLBACK(MYSQL_TYPE_LONG_BLOB);
						TYPE_CALLBACK(MYSQL_TYPE_BLOB);
						TYPE_CALLBACK(MYSQL_TYPE_GEOMETRY);
						TYPE_CALLBACK(MYSQL_TYPE_VAR_STRING);
						TYPE_CALLBACK(MYSQL_TYPE_VARCHAR);
						TYPE_CALLBACK(MYSQL_TYPE_DATETIME2);
						TYPE_CALLBACK(MYSQL_TYPE_STRING);
#undef TYPE_CALLBACK
						case MAX_NO_FIELD_TYPES:
							// This is why you don't the end of the enum as member!
#ifdef NDEBUG
							[[fallthrough]];
						default:
#endif
							throw std::logic_error("Unknown type: " + std::to_string(type));
					}
				}
				++nullIter;
			}
			++colIter;
		}
	}
}