1
0
mirror of https://github.com/fumiama/fumidb.git synced 2026-06-08 20:10:25 +08:00

finish insert row & find row by pk

This commit is contained in:
源文雨
2022-05-04 13:48:57 +08:00
parent b33e5dbe73
commit 9a589ea33e
5 changed files with 331 additions and 22 deletions

View File

@@ -17,20 +17,51 @@ static int _calc_index_size(type_t t) {
switch(t&7) {
case TYPE_INT8:
return INT8_INDEX_SZ+10;
break;
case TYPE_INT16:
return INT16_INDEX_SZ+10 + INT16_BITMAP_SZ+8*2;
break;
case TYPE_INT32:
case TYPE_FLOAT:
case TYPE_INT64:
case TYPE_DOUBLE:
case TYPE_STRING:
return PAGESZ+8;
break;
case TYPE_BINARY: // 不能创建索引
default:
return EOF;
break;
}
}
// 计算本类型占用的空间
static int _calc_type_size(type_t t) {
switch(t&7) {
case TYPE_INT8:
return (int)(!(t&EXTYPE_NONNULL))+1+((t&EXTYPE_UNIQUE)?0:8);
break;
case TYPE_INT16:
return (int)(!(t&EXTYPE_NONNULL))+2+((t&EXTYPE_UNIQUE)?0:8);
break;
case TYPE_INT32:
case TYPE_FLOAT:
return (int)(!(t&EXTYPE_NONNULL))+4;
break;
case TYPE_INT64:
case TYPE_DOUBLE:
return (int)(!(t&EXTYPE_NONNULL))+8;
break;
case TYPE_STRING:
return (int)(!(t&EXTYPE_NONNULL))+8+2;
break;
case TYPE_BINARY:
return (int)(!(t&EXTYPE_NONNULL))+2;
break;
}
return 0;
}
// 为 t 类型创建索引,写入 index_ptr
// 返回:
// 1 失败,详见 errno
@@ -75,7 +106,8 @@ static int _remove_index_type(int fd, type_t t, uint64_t ptr) {
return sz;
}
// 创建表,可变参数为本表的一行的 types详见 types.h
// 创建表,可变参数 list 为本表的一行的 types详见 types.h
// list 以 type_t 为单元,遇到 uint64_t ptr 时偏移 +8
// 如果 types 为外键,需要紧跟一个 uint64_t ptr
// 指示外键链接到的表位置
// len(buf) >= 4096+8+2=4106
@@ -123,7 +155,7 @@ void* create_table(int fd, char* buf, const char* name, int row_len, const void*
printf("fill[%d]: %d\n", ap, t);
#endif
if(t & EXTYPE_FOREIGNKEY) { // 是外键,还有一个参数
ptr = ((uint64_t*)list)[ap];
ptr = le64(list+ap);
#ifdef DEBUG
printf("fill[%d]: %016llx\n", ap, ptr);
#endif
@@ -140,7 +172,7 @@ void* create_table(int fd, char* buf, const char* name, int row_len, const void*
printf("fill[%d]: %d\n", ap, t);
#endif
if(t & EXTYPE_FOREIGNKEY) { // 是外键,还有一个参数
ptr = ((uint64_t*)list)[ap];
ptr = le64(list+ap);
#ifdef DEBUG
printf("fill[%d]: %016llx\n", ap, ptr);
#endif
@@ -276,16 +308,191 @@ int remove_table_index(int fd, void* table, uint16_t pos) {
return sync_block(fd, table);
}
#define DEBUG
// 插入一行,如果 pk 有值则替换
// list 以 key_t 为单元
// 如果当前项有 nullable 属性,需要在此项之前
// 加一个 int isavailable标记本项是否有值
// 加一个 key_t isavailable标记本项是否有值
// 如果 isavailable==0后面不再跟有本项数据
// 如果 isavailable!=0则在后面附加数据
// 如果 val 不为 string/binary直接装填其值
// 否则,值是指向 string/binary 的指针 (const char*)
// 且需要在指针之前提供一个 key_t 参数指示其大小
// 返回:
// 0 失败,详见 errno
// ptr 本行插入的位置
uint64_t insert_row(int fd, void* table, int row_len, const void* list) {
return 0;
uint64_t insert_row(int fd, void* table, const key_t* list) {
int len = 8+2+le16(table+8);
int rlen = le16(table+len);
int sz = 0; // 本行长度
int ap = 0;
len += 2;
uint64_t ptr = *(uint64_t*)(table+len+rlen);
int indexsz = _calc_index_size(((type_t*)table)[len]);
if(indexsz <= 0) return 0;
void* indexbuf = malloc(indexsz);
if(!indexbuf) return 0;
void* index = load_index(fd, ((type_t*)table)[len], ptr, indexbuf);
if(index == NULL) {
free(indexbuf);
return 0;
}
ptr = find_item_by_key(fd, ((type_t*)table)[len], index, list[0]);
for(int i = 0; i < rlen; i++) {
type_t t = ((type_t*)table)[len+i];
#ifdef DEBUG
printf("type: %d, ", (int)t);
#endif
int isnull = 0;
sz += _calc_type_size(t);
#ifdef DEBUG
printf("sz: %d, ", sz);
#endif
if(!(t&EXTYPE_NONNULL)) { // 可空,读取是否为空
isnull = !((int)(list[ap++]));
#ifdef DEBUG
printf("isnull: %s, ", isnull?"true":"false");
#endif
}
if((t&7) >= TYPE_STRING) { // 是 string/binary多读取一个长度
int blen = (int)(list[ap++]);
#ifdef DEBUG
printf("blen: %d, ", blen);
#endif
if(blen > PAGESZ/2 || blen <= 0) { // 长度超标
errno = EFBIG;
free(indexbuf);
return 0;
}
sz += blen;
}
if(!isnull) {
#ifdef DEBUG
printf("skip key: %lld, ", list[ap]);
#endif
ap++; // 跳过读取真实值
}
#ifdef DEBUG
printf("ap: %d\n", ap);
#endif
}
#ifdef DEBUG
printf("total size: %d\n", sz);
#endif
if(sz <= 0 || sz > PAGESZ) { // 总长超出一页,无法插入
errno = EFBIG;
free(indexbuf);
return 0;
}
void* buf = malloc(sz+10);
if(!buf) {
free(indexbuf);
return 0;
}
void* blk = ptr?get_block(fd, sz, ptr, buf):alloc_block(fd, sz, buf);
if(blk == NULL) {
free(indexbuf);
free(buf);
return 0;
}
ap = 0;
int p = 0;
for(int i = 0; i < rlen; i++) {
type_t t = ((type_t*)table)[len+i];
int blen;
if(!(t&EXTYPE_NONNULL)) { // 可空,读取是否为空
int isnull = !((int)(list[ap++]));
((uint8_t*)blk)[p++] = isnull;
if(isnull) {
p += _calc_type_size(t)-1; // 跳过本项
if((t&7) >= TYPE_STRING) { // 是 string/binary多读取一个长度
blen = (int)(list[ap++]);
if(blen > PAGESZ/2 || blen <= 0) { // 长度超标
errno = EFBIG;
free(indexbuf);
return 0;
}
p += blen;
}
#ifdef DEBUG
printf("skip to: %d\n", p);
#endif
continue;
}
}
switch(t&7) {
case TYPE_INT8:
if(!(t&EXTYPE_UNIQUE)) p += 8; // 跳过下一个哈希相同的数据项的指针
((uint8_t*)blk)[p++] = (uint8_t)(list[ap++]);
break;
case TYPE_INT16:
if(!(t&EXTYPE_UNIQUE)) p += 8; // 跳过下一个哈希相同的数据项的指针
putle16(blk+p, list[ap++]);
p += 2;
break;
case TYPE_INT32:
case TYPE_FLOAT:
putle32(blk+p, list[ap++]);
p += 4;
break;
case TYPE_INT64:
case TYPE_DOUBLE:
putle64(blk+p, list[ap++]);
p += 8;
break;
case TYPE_STRING: // 跳过哈希相同指针
p += 8;
case TYPE_BINARY: // 是 string/binary多读取一个长度
blen = (int)(list[ap++]);
#ifdef DEBUG
printf("blen: %d, ", blen);
#endif
if(blen > PAGESZ/2 || blen <= 0) { // 长度超标
errno = EFBIG;
free(indexbuf);
return 0;
}
putle16(blk+p, blen); // 写入长度
p += 2;
char* field = (char*)(list[ap++]); // 读取指针
#ifdef DEBUG
printf("p: %d, ", p);
#endif
memcpy(blk+p, field, blen); // 复制
#ifdef DEBUG
printf("copy field: ");
for(int i = 0; i < blen; i++) printf("%02x ", (int)((unsigned char)(field[i])));
putchar('\n');
#endif
p += blen;
break;
}
}
#ifdef DEBUG
printf("total size: %d\n", p);
#endif
if(sync_block(fd, blk)) { // 将行写入文件
free(indexbuf);
free(buf);
return 0;
}
ptr = le64(buf);
if(insert_item(fd, ((type_t*)table)[len], index, list[0], ptr)) { // 插入 pk 索引
free(indexbuf);
free(buf);
return 0;
}
// TODO: 同时插入其它已创建索引的列的索引
free(indexbuf);
free(buf);
return ptr;
}
// 根据主键的匹配值查找行
@@ -295,7 +502,32 @@ uint64_t insert_row(int fd, void* table, int row_len, const void* list) {
// 0 失败,详见 errno
// ptr 行所在位置
uint64_t find_row_by_pk(int fd, void* table, key_t k) {
return 0;
int len = 8+2+le16(table+8);
int rlen = le16(table+len);
len += 2;
uint64_t ptr = *(uint64_t*)(table+len+rlen);
#ifdef DEBUG
printf("indexptr: %016llx, ", ptr);
#endif
int indexsz = _calc_index_size(((type_t*)table)[len]);
#ifdef DEBUG
printf("indexsz: %d, ", indexsz);
#endif
if(indexsz <= 0) return 0;
void* indexbuf = malloc(indexsz);
if(!indexbuf) return 0;
void* index = load_index(fd, ((type_t*)table)[len], ptr, indexbuf);
if(index == NULL) {
free(indexbuf);
return 0;
}
ptr = find_item_by_key(fd, ((type_t*)table)[len], index, k);
#ifdef DEBUG
printf("ptr: %016llx\n", ptr);
#endif
free(indexbuf);
return ptr;
}
// 根据任意匹配值遍历查找行