Skip to content

Commit 9f93a83

Browse files
committed
Move common fns to sqlite_common.h
1 parent 9dda8fe commit 9f93a83

4 files changed

Lines changed: 354 additions & 378 deletions

File tree

README.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -146,16 +146,22 @@ int main() {
146146
uint8_t rec_buf[500];
147147
int rec_len;
148148

149-
age = 19; maths = 80; physics = 69; chemistry = 98; average = round((maths + physics + chemistry) * 100 / 3) / 100;
150-
rec_len = sqib.make_new_rec(rec_buf, 6, (const void *[]) {"Robert", &age, &maths, &physics, &chemistry, &average}, NULL, col_types);
149+
age = 19; maths = 80; physics = 69; chemistry = 98;
150+
average = round((maths + physics + chemistry) * 100 / 3) / 100;
151+
const void *rec_values[] = {"Robert", &age, &maths, &physics, &chemistry, &average};
152+
rec_len = sqib.make_new_rec(rec_buf, 6, rec_values, NULL, col_types);
151153
sqib.put(rec_buf, -rec_len, NULL, 0);
152154

153-
age = 20; maths = 82; physics = 99; chemistry = 83; average = round((maths + physics + chemistry) * 100 / 3) / 100;
154-
rec_len = sqib.make_new_rec(rec_buf, 6, (const void *[]) {"Barry", &age, &maths, &physics, &chemistry, &average}, NULL, col_types);
155+
age = 20; maths = 82; physics = 99; chemistry = 83;
156+
average = round((maths + physics + chemistry) * 100 / 3) / 100;
157+
rec_values[0] = "Barry";
158+
rec_len = sqib.make_new_rec(rec_buf, 6, rec_values, NULL, col_types);
155159
sqib.put(rec_buf, -rec_len, NULL, 0);
156160

157-
age = 23; maths = 84; physics = 89; chemistry = 74; average = round((maths + physics + chemistry) * 100 / 3) / 100;
158-
rec_len = sqib.make_new_rec(rec_buf, 6, (const void *[]) {"Elizabeth", &age, &maths, &physics, &chemistry, &average}, NULL, col_types);
161+
age = 23; maths = 84; physics = 89; chemistry = 74;
162+
average = round((maths + physics + chemistry) * 100 / 3) / 100;
163+
rec_values[0] = "Elizabeth";
164+
rec_len = sqib.make_new_rec(rec_buf, 6, rec_values, NULL, col_types);
159165
sqib.put(rec_buf, -rec_len, NULL, 0);
160166

161167
return 0;

src/sqlite_common.h

Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
#ifndef SIARA_SQLITE_COMMON
2+
#define SIARA_SQLITE_COMMON
3+
4+
#include <string>
5+
#include <stdlib.h>
6+
#include <stdint.h>
7+
8+
#include "util.h"
9+
10+
const int8_t col_data_lens[] = {0, 1, 2, 3, 4, 6, 8, 8, 0, 0};
11+
12+
enum {SQLT_TYPE_NULL = 0, SQLT_TYPE_INT8, SQLT_TYPE_INT16, SQLT_TYPE_INT24, SQLT_TYPE_INT32, SQLT_TYPE_INT48, SQLT_TYPE_INT64,
13+
SQLT_TYPE_REAL, SQLT_TYPE_INT0, SQLT_TYPE_INT1, SQLT_TYPE_BLOB = 12, SQLT_TYPE_TEXT = 13};
14+
15+
enum {SQLT_RES_OK = 0, SQLT_RES_ERR = -1, SQLT_RES_INV_PAGE_SZ = -2,
16+
SQLT_RES_TOO_LONG = -3, SQLT_RES_WRITE_ERR = -4, SQLT_RES_FLUSH_ERR = -5};
17+
18+
enum {SQLT_RES_SEEK_ERR = -6, SQLT_RES_READ_ERR = -7,
19+
SQLT_RES_INVALID_SIG = -8, SQLT_RES_MALFORMED = -9,
20+
SQLT_RES_NOT_FOUND = -10, SQLT_RES_NOT_FINALIZED = -11,
21+
SQLT_RES_TYPE_MISMATCH = -12, SQLT_RES_INV_CHKSUM = -13,
22+
SQLT_RES_NEED_1_PK = -14, SQLT_RES_NO_SPACE = -15};
23+
24+
class sqlite_common {
25+
26+
public:
27+
// Writes given value at given pointer in Sqlite format
28+
static uint16_t write_data(uint8_t *data_ptr, int type, const void *val, uint16_t len) {
29+
if (val == NULL || type == SQLT_TYPE_NULL
30+
|| type == SQLT_TYPE_INT0 || type == SQLT_TYPE_INT1)
31+
return 0;
32+
if (type >= SQLT_TYPE_INT8 && type <= SQLT_TYPE_INT64) {
33+
switch (type) {
34+
case SQLT_TYPE_INT8:
35+
util::write_uint8(data_ptr, *((int8_t *) val));
36+
break;
37+
case SQLT_TYPE_INT16:
38+
util::write_uint16(data_ptr, *((int16_t *) val));
39+
break;
40+
case SQLT_TYPE_INT24:
41+
util::write_int24(data_ptr, *((int32_t *) val));
42+
break;
43+
case SQLT_TYPE_INT32:
44+
util::write_uint32(data_ptr, *((int32_t *) val));
45+
break;
46+
case SQLT_TYPE_INT48:
47+
util::write_int48(data_ptr, *((int64_t *) val));
48+
break;
49+
case SQLT_TYPE_INT64:
50+
util::write_uint64(data_ptr, *((int64_t *) val));
51+
break;
52+
}
53+
} else
54+
if (type == SQLT_TYPE_REAL && len == 4) {
55+
// Assumes float is represented in IEEE-754 format
56+
uint64_t bytes64 = util::float_to_double(val);
57+
util::write_uint64(data_ptr, bytes64);
58+
len = 8;
59+
} else
60+
if (type == SQLT_TYPE_REAL && len == 8) {
61+
// TODO: Assumes double is represented in IEEE-754 format
62+
uint64_t bytes = *((uint64_t *) val);
63+
util::write_uint64(data_ptr, bytes);
64+
} else
65+
memcpy(data_ptr, val, len);
66+
return len;
67+
}
68+
69+
// Initializes the buffer as a B-Tree Leaf Index
70+
static void init_bt_idx_interior(uint8_t *ptr, int block_size, int resv_bytes) {
71+
ptr[0] = 2; // Interior index b-tree page
72+
util::write_uint16(ptr + 1, 0); // No freeblocks
73+
util::write_uint16(ptr + 3, 0); // No records yet
74+
util::write_uint16(ptr + 5, (block_size - resv_bytes == 65536 ? 0 : block_size - resv_bytes)); // No records yet
75+
util::write_uint8(ptr + 7, 0); // Fragmented free bytes
76+
util::write_uint32(ptr + 8, 0); // right-most pointer
77+
}
78+
79+
// Initializes the buffer as a B-Tree Leaf Index
80+
static void init_bt_idx_leaf(uint8_t *ptr, int block_size, int resv_bytes) {
81+
ptr[0] = 10; // Leaf index b-tree page
82+
util::write_uint16(ptr + 1, 0); // No freeblocks
83+
util::write_uint16(ptr + 3, 0); // No records yet
84+
util::write_uint16(ptr + 5, (block_size - resv_bytes == 65536 ? 0 : block_size - resv_bytes)); // No records yet
85+
util::write_uint8(ptr + 7, 0); // Fragmented free bytes
86+
}
87+
88+
// Initializes the buffer as a B-Tree Leaf Table
89+
static void init_bt_tbl_leaf(uint8_t *ptr, int block_size, int resv_bytes) {
90+
ptr[0] = 13; // Leaf Table b-tree page
91+
util::write_uint16(ptr + 1, 0); // No freeblocks
92+
util::write_uint16(ptr + 3, 0); // No records yet
93+
util::write_uint16(ptr + 5, (block_size - resv_bytes == 65536 ? 0 : block_size - resv_bytes)); // No records yet
94+
util::write_uint8(ptr + 7, 0); // Fragmented free bytes
95+
}
96+
97+
static int get_offset(uint8_t block[]) {
98+
return (block[0] == 2 || block[0] == 5 || block[0] == 10 || block[0] == 13 ? 0 : 100);
99+
}
100+
101+
static int get_data_len(int i, const uint8_t types[], const void *values[]) {
102+
if (types == NULL || types[i] >= 10)
103+
return strlen((const char *) values[i]);
104+
return col_data_lens[types[i]];
105+
}
106+
107+
static int write_new_rec(uint8_t block[], int pos, int64_t rowid, int col_count, const void *values[],
108+
const size_t value_lens[] = NULL, const uint8_t types[] = NULL, uint8_t *ptr = NULL) {
109+
110+
int data_len = 0;
111+
for (int i = 0; i < col_count; i++)
112+
data_len += (value_lens == NULL ? get_data_len(i, types, values) : value_lens[i]);
113+
int hdr_len = 0;
114+
for (int i = 0; i < col_count; i++) {
115+
int val_len_hdr_len = (value_lens == NULL ? get_data_len(i, types, values) : value_lens[i]);
116+
if (types == NULL || types[i] == SQLT_TYPE_TEXT || types[i] == SQLT_TYPE_BLOB) {
117+
val_len_hdr_len = val_len_hdr_len * 2 + (types == NULL ? 13 : types[i]);
118+
}
119+
hdr_len += util::get_vlen_of_uint16(val_len_hdr_len);
120+
}
121+
int offset = get_offset(block);
122+
int hdr_len_vlen = util::get_vlen_of_uint32(hdr_len);
123+
hdr_len += hdr_len_vlen;
124+
int rowid_len = 0;
125+
if (block[offset] == 10 || block[offset] == 13)
126+
rowid_len = util::get_vlen_of_uint64(rowid);
127+
int rec_len = hdr_len + data_len;
128+
int rec_len_vlen = util::get_vlen_of_uint32(rec_len);
129+
130+
int last_pos = 0;
131+
bool is_ptr_given = true;
132+
int blk_hdr_len = (block[offset] == 10 || block[offset] == 13 ? 8 : 12);
133+
if (ptr == NULL) {
134+
is_ptr_given = false;
135+
last_pos = util::read_uint16(block + offset + 5);
136+
if (last_pos == 0)
137+
last_pos = 65536;
138+
int ptr_len = util::read_uint16(block + offset + 3) << 1;
139+
if (offset + blk_hdr_len + ptr_len + rec_len + rec_len_vlen >= last_pos)
140+
return SQLT_RES_NO_SPACE;
141+
last_pos -= rec_len;
142+
last_pos -= rec_len_vlen;
143+
last_pos -= rowid_len;
144+
ptr = block + last_pos;
145+
}
146+
147+
if (!is_ptr_given) {
148+
ptr += util::write_vint32(ptr, rec_len);
149+
if (block[offset] == 10 || block[offset] == 13)
150+
ptr += util::write_vint64(ptr, rowid);
151+
}
152+
ptr += util::write_vint32(ptr, hdr_len);
153+
for (int i = 0; i < col_count; i++) {
154+
uint8_t type = (types == NULL ? SQLT_TYPE_TEXT : types[i]);
155+
int value_len = (value_lens == NULL ? get_data_len(i, types, values) : value_lens[i]);
156+
int col_len_in_hdr = (type == SQLT_TYPE_TEXT || type == SQLT_TYPE_BLOB)
157+
? value_len * 2 + type : type;
158+
ptr += util::write_vint32(ptr, col_len_in_hdr);
159+
}
160+
for (int i = 0; i < col_count; i++) {
161+
if (value_lens == NULL || value_lens[i] > 0) {
162+
ptr += write_data(ptr, types == NULL ? SQLT_TYPE_TEXT : types[i],
163+
values[i], value_lens == NULL ? get_data_len(i, types, values) : value_lens[i]);
164+
}
165+
}
166+
167+
// if pos given, update record count, last data pos and insert record
168+
if (last_pos > 0 && pos >= 0) {
169+
int rec_count = util::read_uint16(block + offset + 3);
170+
util::write_uint16(block + offset + 3, rec_count + 1);
171+
util::write_uint16(block + offset + 5, last_pos);
172+
uint8_t *ins_ptr = block + offset + blk_hdr_len + pos * 2;
173+
memmove(ins_ptr + 2, ins_ptr, (rec_count - pos) * 2);
174+
util::write_uint16(ins_ptr, last_pos);
175+
}
176+
177+
return is_ptr_given ? rec_len : last_pos;
178+
179+
}
180+
181+
// Writes data into buffer to form first page of Sqlite db
182+
static void fill_page0(uint8_t master_block[], int total_col_count, int pk_col_count, int block_size,
183+
int page_resv_bytes, const std::string& col_names, const std::string& table_name) {
184+
185+
if (block_size % 512 || block_size < 512 || block_size > 65536)
186+
throw SQLT_RES_INV_PAGE_SZ;
187+
188+
// 100 uint8_t header - refer https://www.sqlite.org/fileformat.html
189+
memcpy(master_block, "SQLite format 3\0", 16);
190+
util::write_uint16(master_block + 16, block_size == 65536 ? 1 : (uint16_t) block_size);
191+
master_block[18] = 1;
192+
master_block[19] = 1;
193+
master_block[20] = page_resv_bytes;
194+
master_block[21] = 64;
195+
master_block[22] = 32;
196+
master_block[23] = 32;
197+
//write_uint32(master_block + 24, 0);
198+
//write_uint32(master_block + 28, 0);
199+
//write_uint32(master_block + 32, 0);
200+
//write_uint32(master_block + 36, 0);
201+
//write_uint32(master_block + 40, 0);
202+
memset(master_block + 24, '\0', 20); // Set to zero, above 5
203+
util::write_uint32(master_block + 28, 2); // TODO: Update during finalize
204+
util::write_uint32(master_block + 44, 4);
205+
//write_uint16(master_block + 48, 0);
206+
//write_uint16(master_block + 52, 0);
207+
memset(master_block + 48, '\0', 8); // Set to zero, above 2
208+
util::write_uint32(master_block + 56, 1);
209+
// User version initially 0, set to table leaf count
210+
// used to locate last leaf page for binary search
211+
// and move to last page.
212+
util::write_uint32(master_block + 60, 0);
213+
util::write_uint32(master_block + 64, 0);
214+
// App ID - set to 0xA5xxxxxx where A5 is signature
215+
// till it is implemented
216+
util::write_uint32(master_block + 68, 0xA5000000);
217+
memset(master_block + 72, '\0', 20); // reserved space
218+
util::write_uint32(master_block + 92, 105);
219+
util::write_uint32(master_block + 96, 3016000);
220+
memset(master_block + 100, '\0', block_size - 100); // Set remaining page to zero
221+
222+
// master table b-tree
223+
init_bt_tbl_leaf(master_block + 100, block_size, page_resv_bytes);
224+
225+
// write table script record
226+
std::string tbl_name = "idx1";
227+
if (!table_name.empty())
228+
tbl_name = table_name;
229+
// write table script record
230+
int col_count = 5;
231+
// if (table_script) {
232+
// uint16_t script_len = strlen(table_script);
233+
// if (script_len > block_size - 100 - page_resv_bytes - 8 - 10)
234+
// return SQLT_RES_TOO_LONG;
235+
// set_col_val(4, SQLT_TYPE_TEXT, table_script, script_len);
236+
// } else {
237+
int table_name_len = tbl_name.length();
238+
// len("CREATE TABLE ") + table_name_len + len(" (")
239+
// + len("PRIMARY KEY (") + len(") WITHOUT ROWID")
240+
size_t script_len = 13 + table_name_len + 2 + 13 + 15;
241+
script_len += col_names.length();
242+
script_len += 2; // len(", ")
243+
int pk_end_pos = 0;
244+
for (int i = 0, comma_count = 0; i < col_names.length(); i++) {
245+
if (col_names[i] == ',')
246+
comma_count++;
247+
if (comma_count == pk_col_count) {
248+
pk_end_pos = i;
249+
break;
250+
}
251+
}
252+
if (pk_end_pos == 0)
253+
pk_end_pos = col_names.length();
254+
script_len += pk_end_pos;
255+
script_len++; // len(")")
256+
// 100 byte header, 2 byte ptr, 3 byte rec/hdr vlen, 1 byte rowid
257+
// 6 byte hdr len, 5 byte "table", twice table name, 4 byte uint32 root
258+
if (script_len > (block_size - 100 - page_resv_bytes - 8
259+
- 2 - 3 - 1 - 6 - 5 - tbl_name.length() * 2 - 4))
260+
throw SQLT_RES_TOO_LONG;
261+
uint8_t *script_loc = master_block + block_size - page_resv_bytes - script_len;
262+
uint8_t *script_pos = script_loc;
263+
memcpy(script_pos, "CREATE TABLE ", 13);
264+
script_pos += 13;
265+
memcpy(script_pos, tbl_name.c_str(), table_name_len);
266+
script_pos += table_name_len;
267+
*script_pos++ = ' ';
268+
*script_pos++ = '(';
269+
memcpy(script_pos, col_names.c_str(), col_names.length());
270+
script_pos += col_names.length();
271+
*script_pos++ = ',';
272+
*script_pos++ = ' ';
273+
memcpy(script_pos, "PRIMARY KEY (", 13);
274+
script_pos += 13;
275+
memcpy(script_pos, col_names.c_str(), pk_end_pos);
276+
script_pos += pk_end_pos;
277+
*script_pos++ = ')';
278+
memcpy(script_pos, ") WITHOUT ROWID", 15);
279+
script_pos += 15;
280+
// }
281+
int32_t root_page_no = 2;
282+
const void *master_rec_values[] = {"table", tbl_name.c_str(), tbl_name.c_str(), &root_page_no, script_loc};
283+
const size_t master_rec_col_lens[] = {5, table_name.length(), table_name.length(), sizeof(root_page_no), script_len};
284+
const uint8_t master_rec_col_types[] = {SQLT_TYPE_TEXT, SQLT_TYPE_TEXT, SQLT_TYPE_TEXT, SQLT_TYPE_INT32, SQLT_TYPE_TEXT};
285+
int res = write_new_rec(master_block, 0, 1, 5, master_rec_values, master_rec_col_lens, master_rec_col_types);
286+
if (res < 0)
287+
throw res;
288+
289+
}
290+
291+
};
292+
293+
#endif

0 commit comments

Comments
 (0)