##一. 总体框架
RedBase是一个轻量级的关系型数据库, 框架的设计思路主要根据斯坦福大学的Database System Implementation(CS346)课程提供的Redbase数据库框架来设计. 主要包含5个模块:
- PageFile(PF)
- RecordManager(RM)
- IndexManager(IX)
- SystemManager(SM)
- QueryManager(QM) 在具体的实现中, 为了遵循模块化程序设计的原则, 将各个模块按照不同的功能分成多个类来实现, 具体实现细节将在后面介绍
- 支持的数据类型: INT, FLOAT, STRING(需要指定大小).
- 数据库的建立和删除,以及数据库的统计信息查询
- 表的建立和删除,以及表的统计信息查询
- 索引的建立和删除
- 使用与MySQL语法相似的SQL语句对表或数据库中的数据执行增、删、改、查操作
开发环境:Visual Studio 2015 编程语言:C++(主要使用C++11推荐语法)
PF模块是系统的最底层模块, 主要向高层次的结构(Index Manager和Record Manager)提供以页为基本单元的文件IO操作. 在该模块中, 主要实现了创建, 删除, 打开和关闭文件四个操作. 对于单个文件(PageFile类)的操作, 必须先从PF模块打开一个PageFile实例为操作对象, 以页(Page)为最小访问单元. PageFile提供了从文件中获取一个新的Page, 获取一个特定页号的Page, 强制更新(Force)文件中特定页号的Page等方法. 实际上, 由于文件系统IO速度比较慢, 为了提高获取数据的速度, PM模块还需要对每个文件维护一个Buffer(BufferManager类). 每个BufferManager实例管理一个PageFile实例以及一个Buffer(用哈希表结构存储在内存中), 上层模块只能通过BufferManager来间接地访问PageFile获取所需Page.
RM模块是管理记录文件的模块, 主要面向Query Manager和System Manager两个模块. RM模块只提供了对记录文件的创建, 删除, 打开和关闭四个操作. 在RedBase的实现中, 每个表中有若干条记录, 一个表中的所有记录必须存在同一个记录文件(RecordFile)中. 对单个记录文件的操作, 必须通过RecordFile实例进行操作. RecordFile提供了对该文件中记录的增删改查四个操作.
IX模块是管理索引的模块, 主要提供了对某个表的属性进行创建, 删除索引, 并对已创建的索引的打开, 关闭四个操作. 关于索引的具体实现, RedBase的索引与大多数数据库引擎类似, 使用B+树作为索引的数据结构, 每个B+树的结点存储在一个Page中, 以达到较高的索引效率. 其他模块对于单个索引的数据插入, 删除, 查询, 必须先通过Index Manager获取一个IndexHandle实例, 并通过这个IndexHandle实例进行操作.
SM模块直接面向Command Parser,提供一些可能会影响整个数据库系统的操作,包括:
- 创建、删除一个数据库/关系表/索引等(DDL)
- 维护系统中各个数据库和表的Catalog
- 从文件中导入数据
- 设置数据库或表的参数
- 输出关系表
QM模块与SM模块类似,主要向Command Parser提供了用于执行特定的SQL操作。当前的实现支持的SQL操作有Select(包括多表联查),Insert,Delete,Update四种操作。操作的执行主要先通过System Manager获取查询表的结构, 分析后通过调用Record Manager的方法查询并解析查询的结果, 返回给Command Parser.
RETCODE CreateFile (const char * fileName); // Create a new file
创建一个新的文件(索引的结点或是记录文件)
RETCODE DestroyFile (const char * fileName); // Destroy a file
删除一个文件
RETCODE OpenFile (const char * fileName, PageFilePtr & fileHandle); // Open a file
打开一个文件并获取该文件的PageFile实例
RETCODE CloseFile (PageFilePtr &fileHandle); // Close a file
关闭一个文件并释放PageFile实例
RETCODE GetThisPage (PageNum pageNum, PagePtr &pageHandle) ;
获取该文件中特定一页, 返回Page实例
RETCODE AllocatePage (PagePtr &pageHandle);
分配一个新的页, 返回Page实例
RETCODE DisposePage (PageNum pageNum);
释放(不再使用)特定的页
RETCODE ForcePage (PageNum page, const PagePtr & pageHande);
强制把一个页写入文件中的特定页中
RETCODE GetPage (PageNum page, PagePtr & pBuffer);
获取一个特定的页, 返回Page实例
RETCODE MarkDirty (PageNum page);
把一个页标记为Dirty(修改过)
RETCODE LockPage (PageNum page);
把一个页锁定在Buffer中
RETCODE UnlockPage (PageNum page);
把一个已锁定的页释放
RETCODE ForcePage (PageNum page);
强制把一个页写入文件
RETCODE FlushPages ( );
把Buffer中的所有页写入文件
RETCODE AllocatePage (PagePtr & page);
分配一个新的页, 返回Page实例
RETCODE DisposePage (PageNum page);
释放特定的页
RETCODE Open (const BufferManagerPtr & ptr );
打开一个记录文件
RETCODE InsertRec (const char *pData, RecordIdentifier &rid);
插入记录
RETCODE DeleteRec (const RecordIdentifier&rid);
删除记录
RETCODE UpdateRec (const Record &rec);
修改一条记录
RETCODE GetRec (const RecordIdentifier &rid, Record &rec) const;
获取一条记录
RETCODE ForcePages (PageNum pageNum) const;
将缓冲区的页重新写回硬盘中
RETCODE CreateFile (const char *fileName, size_t recordSize);
创建文件
RETCODE DestroyFile (const char *fileName);
删除文件
RETCODE OpenFile (const char *fileName, RecordFilePtr &fileHandle);
打开文件
RETCODE CloseFile (RecordFilePtr &fileHandle);
关闭文件
IndexManager 类
RETCODE CreateIndex (const char *fileName, AttrType attrType, int attrLength);
创建一个新的索引
RETCODE DestroyIndex (const char *fileName);
删除一个索引
RETCODE OpenIndex (const char *fileName, IndexHandlePtr &indexHandle);
打开数据文件中的索引
RETCODE CloseIndex (IndexHandlePtr &indexHandle);
关闭索引
IndexHandle类
RETCODE InsertEntry (void *pData, const RecordIdentifier & rid);
插入索引(B+树算法)
RETCODE DeleteEntry (void *pData, const RecordIdentifier & rid);
删除索引
RETCODE ForcePages ( );
拷贝整棵B+树到磁盘
RETCODE CreateDb (const char * dbName, PageFileManagerPtr & pfMgr);
创建一个新的数据库
RETCODE OpenDb (const char *dbName);
打开一个数据库
RETCODE CloseDb ( );
关闭当前打开的数据库
RETCODE CreateTable (const char *relName, Create relation, int attrCount, AttrInfo *attributes);
(在当前打开的数据库中)创建表
RETCODE DropTable (const char *relName);
删除表
RETCODE CreateIndex (const char *relName, const char *attrName);
对某个表的一个属性建立索引
RETCODE DropIndex (const char *relName, Destroy index, const char *attrName);
删除索引
RETCODE Select (
int nSelAttrs, // 查询的属性个数
const RelAttr selAttrs[], // 查询的属性
int nRelations, // 查询的关系表个数
const char * const relations[], // 查询的关系表
int nConditions, // 查询的条件个数
const Condition conditions[]); // 查询的具体条件
根据传入的参数执行查询操作。
RETCODE Insert (const char *relName, // 将要插入的关系表
int nValues, // 插入的属性值个数
const Value values[]); // 插入的值
对一个特定的表执行插入操作。
RETCODE Delete (const char *relName, // 将要删除记录的关系表
int nConditions, // 删除的条件个数
const Condition conditions[]); // 删除的具体条件
对一个特定的表以特定的条件删除记录
RETCODE Update (const char *relName, // 将要更新的关系
const RelAttr &updAttr, // 更新的属性
const int bIsValue, // 标记用来赋值的是常量(rhsValue)还是其他记录的值(rhsRelAttr)
const RelAttr &rhsRelAttr, // 用来赋值的记录值
const Value &rhsValue, // 用来赋值的常量
int nConditions, // 赋值的条件个数
const Condition conditions[]); // 赋值的具体条件
更新一个表中满足条件的记录
create table relName(attrName1 Type1, attrName2 Type2, ..., attrNameN TypeN);
drop table relName;
create index relName(attrName);
drop index relName(attrName);
print relName;
Select A1, A2, …, Am
From R1, R2, …, Rn
[Where A1’ comp1 AV1 And A2’ comp2 AV2 And … And Ak’ compk AVk];
Insert Into relName Values (V1, V2, …, Vn);
Update relName
Set attrName = AV
[Where A1 comp1 AV1 And A2 comp2 AV2 And … And Ak compk AVk];
Delete From relName
[Where A1 comp1 AV1 And A2 comp2 AV2 And … And Ak compk AVk];
创建一张students表, 其中有三个属性, id和age均为int型(i), name为char(20)类型.
检测删除结果 ![enter image description here](https://lh3.googleusercontent.com/FzLgK3ocpoG7jxgMuBX78oeuoCfbS867jv8zH1RZZSNoNLVekmznJJnj0MQ_On6uHqJJULQd=s0 "_select3.PNG")