mirror of
https://github.com/fumiama/fumidb.git
synced 2026-06-05 00:32:44 +08:00
add some funcs of table
This commit is contained in:
10
api/table.md
10
api/table.md
@@ -8,16 +8,16 @@
|
||||
│ table name length │ name of the table ( variable length ) │
|
||||
├─────────────────────┼──────────┬──────────┬──────────┬──────────┬──────────┬──────────┤
|
||||
│ │ type of │ type of │ type of │ type of │ type of │ type of │
|
||||
│ table column length │ column │ column │ column │ column │ column │ column │
|
||||
│ table row length │ row │ row │ row │ row │ row │ row │
|
||||
│ │ No.1 │ No.2 │ No.3 │ No.4 │ No... │ No.N │
|
||||
├─────────────────────┴──────────┴──────────┴──────────┴──────────┴──────────┴──────────┤
|
||||
│ index pointer of pk ( this pointer will never be zero ) │
|
||||
├───────────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ index pointer of column No.2 ( if it's zero, there is no index for this column ) │
|
||||
│ index pointer of row No.2 ( if it's zero, there is no index for this row ) │
|
||||
├───────────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ index pointer of column No... ( if it's zero, there is no index for this column ) │
|
||||
│ index pointer of row No... ( if it's zero, there is no index for this row ) │
|
||||
├───────────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ index pointer of column No.N ( if it's zero, there is no index for this column ) │
|
||||
│ index pointer of row No.N ( if it's zero, there is no index for this row ) │
|
||||
├───────────────────────────────────────────────────────────────────────────────────────┤
|
||||
│ index pointer of first foreign key ( if available ) │
|
||||
├───────────────────────────────────────────────────────────────────────────────────────┤
|
||||
@@ -31,7 +31,7 @@
|
||||
> 区块长度固定,但是不同索引类型有所不同
|
||||
详见[索引格式](/api/index.md)。
|
||||
### 表项
|
||||
> 区块长度固定,为`8+len(column1)+len(column2)+...+len(columnN)`字节
|
||||
> 区块长度固定,为`8+len(row 1)+len(row 2)+...+len(row N)`字节
|
||||
为方便遍历,数据表项以uint64的指针开头,代表下一项的地址。接下来按照[数据类型](/api/types.md)中规定的存储格式依次附加第一项、第二项直到第N项的值。
|
||||
#### 表项的增加
|
||||
优先附加到上一个表项末尾。如无法实现,则从空区块选取一个,或附加到整个文件末尾。
|
||||
|
||||
@@ -25,6 +25,8 @@ int set_first_unused_block(int fd, uint64_t ptr);
|
||||
// 获得 ptr of unused blk 字段
|
||||
uint64_t get_first_unused_block(int fd);
|
||||
|
||||
uint64_t get_next_unused_block(int fd, uint64_t ptr);
|
||||
|
||||
// 设置 ptr of next table 字段
|
||||
// 返回:
|
||||
// 0 成功
|
||||
@@ -35,4 +37,6 @@ int set_first_table(int fd, uint64_t ptr);
|
||||
// 获得 ptr of next table 字段
|
||||
uint64_t get_first_table(int fd);
|
||||
|
||||
uint64_t get_next_table(int fd, uint64_t ptr);
|
||||
|
||||
#endif
|
||||
@@ -7,16 +7,18 @@
|
||||
// 创建表,可变参数为本表的一行的 types,详见 types.h
|
||||
// 如果 types 为外键,需要紧跟一个 uint64_t ptr
|
||||
// 指示外键链接到的表位置
|
||||
// len(buf) >= 4096+8+2=4106
|
||||
// 返回:
|
||||
// NULL 失败,详见 errno
|
||||
// table 指向表头的指针
|
||||
void* create_table(int fd, const char* name, ...);
|
||||
void* create_table(int fd, char* buf, const char* name, uint16_t row_len, ...);
|
||||
|
||||
// 加载 ptr 位置的表
|
||||
// len(buf) >= 4096+8+2=4106
|
||||
// 返回:
|
||||
// NULL 失败,详见 errno
|
||||
// table 指向表头的指针
|
||||
void* load_table(int fd, uint64_t ptr);
|
||||
void* load_table(int fd, char* buf, uint64_t ptr);
|
||||
|
||||
// 获得表名长度,包含结尾0
|
||||
uint16_t get_table_name_length(void* table);
|
||||
@@ -45,7 +47,7 @@ int remove_table_index(int fd, void* table, uint16_t pos);
|
||||
// 返回:
|
||||
// 0 失败,详见 errno
|
||||
// ptr 本行插入的位置
|
||||
uint64_t insert_row(int fd, void* table, ...);
|
||||
uint64_t insert_row(int fd, void* table, uint16_t row_len, ...);
|
||||
|
||||
// 根据主键的匹配值查找行
|
||||
// 如果主键不为 string,k 直接装填其值
|
||||
@@ -63,7 +65,7 @@ uint64_t find_row_by_pk(int fd, void* table, key_t k);
|
||||
// 返回:
|
||||
// 非 0 失败,详见 errno
|
||||
// 0 成功
|
||||
int find_row_by(int fd, void* table, int (*f)(uint64_t), ...);
|
||||
int find_row_by(int fd, void* table, int (*f)(uint64_t), uint16_t row_len, ...);
|
||||
|
||||
// 根据主键的匹配值删除行
|
||||
// 如果主键不为 string,k 直接装填其值
|
||||
@@ -80,6 +82,6 @@ int remove_row_by_pk(int fd, void* table, key_t k);
|
||||
// 返回:
|
||||
// 非 0 失败,详见 errno
|
||||
// 0 成功
|
||||
int remove_row_by(int fd, void* table, ...);
|
||||
int remove_row_by(int fd, void* table, uint16_t row_len, ...);
|
||||
|
||||
#endif
|
||||
@@ -21,6 +21,9 @@
|
||||
typedef uint8_t type_t;
|
||||
typedef uint64_t key_t;
|
||||
|
||||
// 获得本类型 index 相对于 buffer 头的偏移
|
||||
int type_offset(type_t t);
|
||||
|
||||
// 为类型 type 创建索引
|
||||
// 返回:索引头节点的指针 index
|
||||
void* create_index(int fd, type_t t, void* buf);
|
||||
|
||||
12
src/file.c
12
src/file.c
@@ -37,6 +37,12 @@ uint64_t get_first_unused_block(int fd) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
uint64_t get_next_unused_block(int fd, uint64_t ptr) {
|
||||
if(lseek(fd, ptr, SEEK_SET) < 0) return EOF;
|
||||
readle64(fd, ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
int set_first_table(int fd, uint64_t ptr) {
|
||||
uint8_t buf[8];
|
||||
if(lseek(fd, 16, SEEK_SET) < 0) return EOF;
|
||||
@@ -50,3 +56,9 @@ uint64_t get_first_table(int fd) {
|
||||
readle64(fd, ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
uint64_t get_next_table(int fd, uint64_t ptr) {
|
||||
if(lseek(fd, ptr, SEEK_SET) < 0) return EOF;
|
||||
readle64(fd, ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
131
src/table.c
131
src/table.c
@@ -1,23 +1,142 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include "../include/binary.h"
|
||||
#include "../include/file.h"
|
||||
#include "../include/page.h"
|
||||
#include "../include/table.h"
|
||||
#include "../include/types.h"
|
||||
#include "../include/types/int8.h"
|
||||
#include "../include/types/int16.h"
|
||||
|
||||
// 计算索引需要的内存
|
||||
static int _calc_index_size(type_t t) {
|
||||
switch(t&7) {
|
||||
case TYPE_INT8:
|
||||
return INT8_INDEX_SZ+10;
|
||||
case TYPE_INT16:
|
||||
return INT16_INDEX_SZ+10 + INT16_BITMAP_SZ+8*2;
|
||||
case TYPE_INT32:
|
||||
case TYPE_FLOAT:
|
||||
case TYPE_INT64:
|
||||
case TYPE_DOUBLE:
|
||||
case TYPE_STRING:
|
||||
return PAGESZ+8;
|
||||
case TYPE_BINARY: // 不能创建索引
|
||||
default:
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
|
||||
// 为 t 类型创建索引,写入 index_ptr
|
||||
// 返回:
|
||||
// 1 失败,详见 errno
|
||||
// 0 成功
|
||||
static void* _add_index_type(int fd, uint64_t* index_ptr, type_t t) {
|
||||
int sz = _calc_index_size(t);
|
||||
if(sz <= 0) {
|
||||
errno = EINVAL;
|
||||
return EINVAL;
|
||||
}
|
||||
void* buf = malloc(sz);
|
||||
if(buf == NULL) return 1;
|
||||
void* index = create_index(fd, t, buf);
|
||||
*index_ptr = le64(buf);
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 创建表,可变参数为本表的一行的 types,详见 types.h
|
||||
// 如果 types 为外键,需要紧跟一个 uint64_t ptr
|
||||
// 指示外键链接到的表位置
|
||||
// len(buf) >= 4096+8+2=4106
|
||||
// 返回:
|
||||
// NULL 失败,详见 errno
|
||||
// table 指向表头的指针
|
||||
void* create_table(int fd, const char* name, ...) {
|
||||
return NULL;
|
||||
void* create_table(int fd, char* buf, const char* name, uint16_t row_len, ...) {
|
||||
va_list list;
|
||||
|
||||
if(!row_len || row_len > 128) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int len = strlen(name);
|
||||
if(len <= 0 || len >= UINT16_MAX) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* table = alloc_page(fd, buf+2);
|
||||
if(table == NULL) return NULL;
|
||||
|
||||
memset(table, 0, PAGESZ);
|
||||
putle16(table+8, len);
|
||||
memcpy(table+8+2, name, len);
|
||||
len += 8+2;
|
||||
|
||||
uint64_t ptr = get_first_table(fd);
|
||||
while(ptr > 0) ptr = get_next_table(fd, ptr); // 结束时,fd位于最后一个表头+8
|
||||
if(ptr) return NULL; // 发生错误
|
||||
lseek(fd, -8, SEEK_CUR);
|
||||
if(write(fd, buf+2, 8) != 8) return NULL; // 写入新表位置
|
||||
|
||||
putle16(table+len, row_len);
|
||||
len += 2;
|
||||
|
||||
int foreign_cnt = 0;
|
||||
va_start(list, row_len);
|
||||
|
||||
type_t t = va_arg(list, type_t); // 是主键,检查是否有 unique + nonnull 类型修饰符
|
||||
if(!(t&EXTYPE_NONNULL) || !(t&EXTYPE_UNIQUE)) {
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
((type_t*)table)[len] = t; // 填充 type of row No.0
|
||||
if(t & EXTYPE_FOREIGNKEY) { // 是外键,还有一个参数
|
||||
ptr = va_arg(list, uint64_t);
|
||||
putle64(table+len+(int)row_len*(8+1)+8*(foreign_cnt++), ptr);
|
||||
}
|
||||
|
||||
// 为 pk 创建索引
|
||||
if(_add_index_type(fd, table+len+(int)row_len, t)) return NULL;
|
||||
for(int i = 1; i < (int)row_len; i++) {
|
||||
t = va_arg(list, type_t);
|
||||
((type_t*)table)[len+i] = t; // 填充 type of row No.i
|
||||
if(t & EXTYPE_FOREIGNKEY) { // 是外键,还有一个参数
|
||||
ptr = va_arg(list, uint64_t);
|
||||
putle64(table+len+(int)row_len*(8+1)+8*(foreign_cnt++), ptr);
|
||||
}
|
||||
}
|
||||
|
||||
va_end(list);
|
||||
|
||||
len += (int)row_len*(8+1) + 8*foreign_cnt;
|
||||
if(len > PAGESZ-2) {
|
||||
errno = EFBIG;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 写回文件
|
||||
if(sync_page(fd, table)) return NULL;
|
||||
// 回收剩余空间
|
||||
ptr = le64(buf+2);
|
||||
if(PAGESZ - len > 10) add_block(fd, PAGESZ - len, ptr+(uint64_t)len);
|
||||
// 将 page 变为 block
|
||||
putle64(buf, ptr);
|
||||
putle16(buf+8, len);
|
||||
return buf+10;
|
||||
}
|
||||
|
||||
// 加载 ptr 位置的表
|
||||
// len(buf) >= 4096+8+2=4106
|
||||
// 返回:
|
||||
// NULL 失败,详见 errno
|
||||
// table 指向表头的指针
|
||||
void* load_table(int fd, uint64_t ptr) {
|
||||
void* load_table(int fd, char* buf, uint64_t ptr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -59,7 +178,7 @@ int remove_table_index(int fd, void* table, uint16_t pos) {
|
||||
// 返回:
|
||||
// 0 失败,详见 errno
|
||||
// ptr 本行插入的位置
|
||||
uint64_t insert_row(int fd, void* table, ...) {
|
||||
uint64_t insert_row(int fd, void* table, uint16_t row_len, ...) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -81,7 +200,7 @@ uint64_t find_row_by_pk(int fd, void* table, key_t k) {
|
||||
// 返回:
|
||||
// 非 0 失败,详见 errno
|
||||
// 0 成功
|
||||
int find_row_by(int fd, void* table, int (*f)(uint64_t), ...) {
|
||||
int find_row_by(int fd, void* table, int (*f)(uint64_t), uint16_t row_len, ...) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -102,6 +221,6 @@ int remove_row_by_pk(int fd, void* table, key_t k) {
|
||||
// 返回:
|
||||
// 非 0 失败,详见 errno
|
||||
// 0 成功
|
||||
int remove_row_by(int fd, void* table, ...) {
|
||||
int remove_row_by(int fd, void* table, uint16_t row_len, ...) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
18
src/types.c
18
src/types.c
@@ -1,3 +1,4 @@
|
||||
#include "../include/binary.h"
|
||||
#include "../include/types.h"
|
||||
#include "../include/types/int8.h"
|
||||
#include "../include/types/int16.h"
|
||||
@@ -129,6 +130,23 @@ static _remove_by_key_t _remove_item_by_key[] = {
|
||||
remove_item_by_not_impl_key
|
||||
};
|
||||
|
||||
int type_offset(type_t t) {
|
||||
switch(t&7) {
|
||||
case TYPE_INT8:
|
||||
case TYPE_INT16:
|
||||
return -10; // block
|
||||
case TYPE_INT32:
|
||||
case TYPE_FLOAT:
|
||||
case TYPE_INT64:
|
||||
case TYPE_DOUBLE:
|
||||
case TYPE_STRING:
|
||||
return -8; // page
|
||||
case TYPE_BINARY: // 不能创建索引
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void* create_index(int fd, type_t t, void* buf) {
|
||||
return _types_init[t&7](fd, buf);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user