结构声明
结构体声明的 DDL 含义与 C 语言中的结构体完全相同。结构体声明命名一种类型,并指定结构体中元素(称为“字段”)的排列方式,这些字段可以具有不同的类型。结构体和简单类型用作构建数据库对象(类)定义的构建块。结构体还可以用作其他结构体的元素。
注意:与 C 或 C++ 结构体不同,SmartEDB 结构体只能在类对象内实例化,仅作为某个类的对象的一部分而存在。 结构体使用以下语法进行定义:
[direct] struct struct_identifier {
struct-declaration-list
};
其中struct-declaration-list
为:
type-identifier | struct-name| enum element-name [ = value [, element-name [= value]] …];
// 或
vector {type-identifier | struct-name} vector-name;
// 或
[optional] struct-name element-name;
直接结构
直接结构是专门为 C 和 C++ 应用程序设计的一种高效优化方式,特别适用于固定大小的类布局。这意味着类内的数据布局中没有动态对象(例如字符串、矩形、向量、可变二进制和序列的对象)、可选或可为空的字段,或其他结构字段。此外,直接结构不能存储在向量中。
在 SmartEDB 中,结构是一种将多个数据字段组合在一起的方式。当您为类定义普通结构时,这些结构的元素可以通过生成的字段级 _get()
和 _put()
API 进行访问。使用结构的好处是可以将多个逻辑相关的数据字段组织在一起,并将数据库结构映射到应用程序内部,例如创建多个时间序列。
然而,调用单独的 _get()
函数来读取或 _put()
函数来写入所有结构元素可能会带来明显的开销,尤其是在结构元素或数据字段数量较多的情况下。此外,多次调用字段访问器对于大量字段来说可能不太方便。为了简化这一过程,您可以使用 _fixed_get()
和 _fixed_put()
API,它们允许一次性读取或写入多个字段(甚至所有字段),将 DDL 字段映射到生成的 C 结构中。这不仅提高了效率,也为开发人员提供了极大的便利。
实际上,DDL 编译器会生成两个结构:
- 紧凑结构:可通过
#pragma pack
实现,用于在数据库中存储元素。在与应用程序交互时,数据库运行时会从存储中读取/写入每个结构元素,并将其复制到应用程序可见的另一个结构中。 - 对齐到字边界的结构:使用直接结构声明时,DDL 编译器会创建一个单个的 C 语言结构,该结构已根据目标字边界对齐。数据库字典引用结构元素的偏移量,这些偏移量与应用程序的 C 结构元素相对应。这是通过在模式编译时计算目标字大小来实现的。
因此,可以在存储中保留原始的 C 语言结构,并且能够一次性读取/写入整个结构(而不是通过访问器 API)。此外,结构中的元素可以像往常一样进行索引,因为运行时通过指定的字典偏移量来引用字段数据,就好像它们是普通字段一样。实际上,关键在于在 DDL 编译时确定目标架构的字长,并使用它来计算结构字段的偏移量。
可选结构
在 SmartEDB 的术语中,结构体是一组数据元素的集合,这些元素可以被指定为类的一个字段。
可选声明意味着该字段可能存储在数据库中,也可能不存储。SmartEDB 运行时不会为可选结构体字段分配内存,直到应用程序显式地为该字段赋值。只有在提交新事务时,实际数据才会被存储到数据库中。如果字段未存储,运行时不会在数据布局中为其预留空间,除了保留一个 2 字节或 4 字节的引用地址。
在这种情况下,相关的获取方法将返回空指针。在 C API 中,classname_fieldname_read_handle()
和 classname_fieldname_write_handle()
函数将返回错误代码 MCO_E_EMPTYOPTIONAL
。
结构体的内存分配规则与其他所有字段相同。
- 如果类中包含的结构体具有动态字段,则该类将以树形内存布局存储。
- 否则,SmartEDB 运行时将把它作为固定记录存储。
对于可选的结构体字段,与动态字段一样,SmartEDB 总是使用树形内存布局。 要对可选结构体执行操作,应用程序使用与普通结构体相同的 API。在 C API 中为 classname_structname_read_handle()
和 classname_structname_write_handle()
。
唯一的区别在于以下三个方面:
- 要分配一个可选结构体,必须使用
classname_structname_write_handle()
函数向其写入内容以获取写入句柄。 - 如果可选结构体字段尚未分配,
classname_structname_read_handle()
API 可能会返回MCO_E_EMPTYOPTIONAL
错误。 - 使用
classname_fieldname_erase()
API 来释放可选结构体的内存。
至于动态字段,SmartEDB 运行时提供了一种内部机制来实现内存碎片整理,并执行自动压缩,这会减小可选结构的大小,但树状内存布局的开销仍然存在。