本篇介绍MyBase数据库中条件过滤的实现。您可以在 https://github.com/zhangqhn/mybase 下载到MyBase项目源码。
- 数据的抽象
MyBase支持整数、浮点数、字符串数据类型,在介绍条件查询之前我们需要先对数据进行抽象,目标是能用一个数据类型表示所有类型的数据。在MyBase的实现中,这个数据类型是DBVal (dbval.h) 它的定义如下:
typedef struct _DBVal
{
int valType_; // value type , null, int, double, string
int dataLen_; // data length
union {
int64_t intVal_;
double doubleVal_;
const char* strVal_;
} val_;
}DBVal;
valType_ :表示当前存储的值类型,null,int,double还是string。
dataLen_ :表示数据的长度,比如:字符串的长度。
val_ : 中存储对应的值。
将数据值通过DBVal存储后,表的每一行数据就可以表示为一个DBVal的数组,在MyBase中我们将每行数据以:std::vector<DBVal> 来表示,条件查询就可以理解为判断一个std::vector<DBVal>对象是否满足给定的条件。
- 查询条件的抽象
在MyBase中我们简单的将条件抽象为 字段、运算符、运算数。
例如:age > 20 , name = ‘zhangsan’ 等等。
也可以没有运算数,例如: score is not null
在表中,字段的位置已经确定,进一步将查询条件简化为:字段下标、运算符、运算数。
根据上面的内容定义出下面的接口:
class ConditionItem
{
public:
virtual bool GetLogic(const std::vector<DBVal>& vals) = 0;
};
不同的条件只需要定义一个类继承ConditionItem ,执行查询时创建该类的实例并将行数据传递给GetLogic的参数,就可以知道该行数据是否满足指定的条件。
下面以age > 20的示例来说明:
实现在整数类型上执行大于判断的类IntGtCondition:
class IntGtCondition : public ConditionItem
{
public:
IntGtCondition(int fieldPos, int64_t valParam)
{
this->fieldPos_ = fieldPos;
this->valParam_ = valParam;
}
virtual ~IntGtCondition() {}
virtual bool GetLogic(const std::vector<DBVal>& vals)
{
if (VALUE_TYPE::VAL_INT == vals[fieldPos_].valType_)
{
return vals[fieldPos_].val_.intVal_ > valParam_;
}
return false;
}
private:
int fieldPos_;
int64_t valParam_;
};
fieldPos_ 即 字段下标;
valParam_ 即 运算数;
运算符也就是大于;
若表的创建语句如下: CREATE TABLE stuinfo(id int, name string, age int)
那么条件: where age > 20 可以转换为
ConditionItem pCondition = new IntGtCondition(2, 20);
将每行数据分别调用 pCondition的GetLogic 方法即可得到该行数据是否满足 age > 20的条件了。
其他条件的实现类似,具体可以参考源码中:condition.h condition.cpp 文件