查询执行
当使用SQL 引擎初始化页面中介绍的两种方法之一对 SQL 数据库引擎结构进行初始化,此结构将用于对所有 mcosql_*
函数的调用。执行 SQL 查询的主要函数是 mcosql_execute_query()
,它以结构 data_source_t 的形式返回结果集。
然后通过如以下代码片段所示,使用游标从数据源中提取结果集数据:
/* Return the autoid for the Person record with the specified name */
MCO_RET get_person_id( database_t db, char const* name, int64_t* id )
{
status_t status = SQL_OK;
data_source_t data_source;
cursor_t cursor;
record_t record;
status = mcosql_execute_query(db, NULL, &data_source, "select autoid from Person where name=%s",
name);
if ( SQL_OK == status )
{
status = mcosql_get_cursor(data_source, &cursor);
if ( SQL_OK == status )
{
status = mcosql_cursor_move_next(cursor, &record);
if ( SQL_OK == status )
{
// process record
...
}
else if ( NO_MORE_ELEMENTS != status )
{
mcosql_error_handler(status);
}
}
mcosql_release_query_result(data_source);
}
return status;
}
请注意此示例代码中的以下内容:
- 函数
get_person_id()
是一个应用程序级别的函数,旨在返回具有指定名称的 Person 对象的autoid
。Person 记录的模式定义如下:
class Person
{
string name;
string address;
string position;
uint4 salary;
float rating;
autoid_t<Person> manager;
autoid[1000];
tree<name> pk;
};
函数
mcosql_execute_query()
执行 SQL 查询并返回一个状态码;它接受一个可变长度的参数列表,包括:db - 数据库引擎
trans - 事务句柄,或者如果查询要在其自身的单独事务中执行则为 NULL(请参阅“管理事务”部分)。
data_source - 接收结果集的数据源地址
statement - 要执行的 SQL 选择语句
... - 0 个或多个要插入到选择语句中的参数列表。(将值替换到 SQL 语句中的规则在语句参数替换页面中详细说明。)
函数
mcosql_get_cursor()
会在结果集上创建一个游标,而mcosql_cursor_move_next()
用于滚动浏览结果行。当到达结果集末尾时,会返回状态码
NO_MORE_ELEMENTS
完成查询后,必须调用函数
mcosql_release_query_result()
来释放为结果集分配的内存和其他资源。
处理查询结果
处理查询结果集中的行通常需要通过遍历每行的列来提取不同类型的值。然后,必须根据每列值的类型对其进行不同的处理。
在内部,所有整数值都以 64 位值的形式存储。要提取列值,需调用函数 mcosql_get_column_value_as()
将内部值转换为应用程序使用的值。例如,以下调用从结果集的第一列提取值并将其转换为 4 字节整数值:
rc = (MCO_RET)mcosql_get_column_value_as(
record, 0, CT_UINT4,
&value, sizeof(value),
NULL
);
在 SmartESQL 6.5 版本之前,使用 mcosql_get_column_value()
函数来提取列值。此函数要求接收缓冲区为 64 位,即使对于较小的数据类型也是如此。
然而,在 6.5 版本及更高版本中,mcosql_get_column_value()
的参数列表已更改,在大多数情况下不应使用该函数,因为它返回内部类型的“原始”值(例如,假设我们有一个 32 位整数列,这些值将作为 64 位整数返回)。
在 6.5 版本之前,会使用如下代码片段来处理结果集中的列:
/* For each row of the result set, iterate through the columns and display values. */
status = mcosql_get_cursor( data_source, &cursor );
if ( SQL_OK == status )
{
for ( n = 0; SQL_OK == ( status = mcosql_cursor_move_next( cursor, &record ) ); n++ )
{
for (j = 0; j < i; j++)
{
status = mcosql_get_column_value(record, j, &type, &value );
if ( SQL_OK == status )
{
if ( 0 == j )
printf( "\t" );
else
printf( ", " );
print_value(db, type, value);
}
}
printf("\n");
}
if ( NO_MORE_ELEMENTS != status )
{
mcosql_error_handler(status);
}
}
还请注意,在 6.5 版本及更高版本中,mcosql_get_column_value()
的参数列表包含六个参数,而之前的实现版本只有四个参数。
status_t mcosql_get_column_value(
record_t record,
size_t columnNo,
type_t* type,
void* buf,
size_t buf_size,
size_t* value_size
);
其中,buf
接收指定列中存储的值,数据类型在参数 type
中返回。
另外,用于检索 mcocomp 生成的记录标识符的函数 mcosql_get_record_id()
已从 6.5 版本及更高版本中移除,并且之前的函数 mcosql_release_memory()
也不再可用,因为所有内存均由静态块分配器管理。
上面代码片段中突出显示的应用程序级函数 print_value()
已复制如下,以展示如何将不同类型的值显示到输出设备:
/* print the value contained in this database field depending on its type */
void print_value(database_t db, int type, void* value)
{
char buf[MAX_NAME_LENGTH];
switch (type)
{
case CT_NULL:
printf("null");
break;
case CT_BOOL:
printf(*(char*)value ? "true" : "false");
break;
case CT_UINT1:
printf("%u", *(uint1*)value);
break;
case CT_UINT2:
printf("%u", *(uint2*)value);
break;
case CT_UINT4:
printf("%u", *(uint4*)value);
break;
case CT_UINT8:
printf("%" INT8_FORMAT "d", *(int64_t*)value);
break;
case CT_INT1:
printf("%d", *(int1*)value);
break;
case CT_INT2:
printf("%d", *(int2*)value);
break;
case CT_INT4:
printf("%d", *(int4*)value);
break;
case CT_INT8:
printf("%" INT8_FORMAT "d", *(int64_t*)value);
break;
case CT_REAL4:
printf("%.1f", *(float*)value);
break;
case CT_REAL8:
printf("%.1f", *(double*)value);
break;
case CT_STRING:
printf("%s", (char*)value);
break;
case CT_REFERENCE:
{
/* lookup the referenced record and extract its name field */
int64_t id;
mcosql_get_record_id(value, &id);
get_person_name(db, buf, sizeof(buf), &id);
printf("%s", buf);
break;
}
default:
printf("???");
}
}
请注意此示例代码中的以下内容:
- 列类型常量
CT_*
在头文件include/sql/sqlc.h
中定义。 - 用于类型
CT_INT8
和CT_UINT8
的printf()
格式字符串中插入的常量INT8_FORMAT
在头文件include/sql/stdtp.h
中定义,其值为字符串常量“l”
、“ll”
或“I64”
,具体取决于开发系统平台。 - 在此示例中,类型
CT_REFERENCE
被视为对不同 Person 对象的引用,其autoid
包含在函数的值参数中。因此,会执行额外的数据库查找以导航到指定的 Person 记录,并提取然后显示其名称字段。显然,这是特定于此数据库模式和数据模型的应用逻辑。
从结果集行中提取数据
上述示例从每个结果集行中提取单个列值。但通常结果集行包含整个数据库对象,例如在查询select * from Person
中。在这种情况下,可能会编写如下函数来处理结果集:
/* Demonstrate use of the function mcosql_extract_struct() */
MCO_RET get_persons( database_t db, char const* name_like )
{
data_source_t data_source;
cursor_t cursor;
status_t status;
record_t record;
int64_t id;
type_t type;
void* value;
int n;
/* Define a structure with exactly the same components as the Person database class */
struct
{
char * name;
char * address;
char * position;
uint4 salary;
float rating;
autoid_t manager;
} rec;
/* Define a character array to hold possible null indicators if any fields are null */
char null_indicators[10];
printf("\n\tGet Person records with name like '%s':\n", name_like );
status = mcosql_execute_query(db, NULL, &data_source,
"select * from Person where name like %s", name_like );
if ( SQL_OK == status )
{
status = mcosql_get_cursor( data_source, &cursor );
if ( SQL_OK == status )
{
for (n = 0; SQL_OK == ( status = mcosql_cursor_move_next( cursor, &record ) ); n++)
{
/* Extract the structure "rec" from the result set record */
status = mcosql_extract_struct(data_source, record, &rec, sizeof(rec), null_indicators);
printf("\t\t%d. %s: salary=%d, rating = %f\n", n + 1, rec.name, rec.salary, rec.rating);
}
if ( NO_MORE_ELEMENTS != status )
{
mcosql_error_handler(status);
}
}
else
{
fprintf(stderr, "No person found with name like '%s'\n", name_like);
}
mcosql_release_query_result( data_source );
}
return rc;
}
请注意此示例代码中的以下内容:
结构体 record_t record 用于接收由调用
mcosql_cursor_move_next()
函数所获取的结果集行。结构体
rec
的定义与模式文件中定义的数据库对象Person
完全对应。定义此 C 结构体的规则如下:该结构体必须与数据库类具有相同数量且顺序一致的组件。
SmartESQL 假定所有结构体元素采用默认对齐方式;即编译器在没有特殊对齐指令的情况下使用的对齐方式。
数组类型的组件由指向数组值的指针表示。
字符串组件表示为以空字符结尾的 ANSI 字符串。
嵌套结构应由相同的 C 结构体表示。
如果列不属于数据库类,而是某些选择语句表达式或计算的结果,则其类型由以下内容确定:
- 整数类型(char、short、unsigned short、int 等)由 int64_t 类型表示
- 浮点类型(float、double)由 double 类型表示
- 其他类型保持原样表示(不转换为任何其他类型)
对于结果集中的每一行,通过调用函数
mcosql_extract_struct()
将行内容(在record_t
record
中)提取到结构体 rec 中。null_indicators[]
数组用于指示是否有任何列为空值。
除了上述展示的功能之外,还提供了以下用于处理结果集行的功能:
/* Get the current transaction within which the specified data source was produced */
mcosql_get_current_transaction(data_source_t data_source, transaction_t* trans);
/* Get the number of columns in the specified data source */
mcosql_get_number_of_columns(data_source_t data_source, int* n_columns);
/* Get an iterator to iterate over the data source columns */
mcosql_get_column_iterator(data_source_t data_source, column_iterator_t* iterator);
/* Get column information. Move the column iterator to the next position and return name
and type information for the current column */
mcosql_get_column_info(column_iterator_t iterator, type_t* type, char** name);
/* Get column value converted to the specified type. In case of string types,
only a pointer to the zero terminated string will be placed in the buffer
and it remains valid only until mcosql_release_query_result is executed. */
mcosql_get_column_value_as(record_t record, int columnNo, type_t type, void* buffer);
/* Get the value of a structure or array field of the current record for update of
its components. This value remains valid only until mcosql_release_query_result
is executed. This value can be used only as a SQL statement parameter (used
with the '%v' format placeholder). */
mcosql_get_column_value_for_update(record_t record, int columnNo, type_t* type, void* value);
/* Set the value of a specified column */
mcosql_set_column_value(record_t record, int columnNo, type_t type, void* value);
提取数组、向量、结构体、二进制大对象和引用
类型为数组(或向量)、引用、结构体和二进制大对象(blob)的结果集值需要更复杂的处理。以下函数用于处理这些类型的字段。
对于与数据库中数组(或向量)类型字段相对应的结果集列:
/* Get array length */
mcosql_get_array_length(void* array, int* length);
/* Get array element value */
mcosql_get_array_element_value(void* array, int index, type_t* type, void* value);
/* Get array element value for update of its components */
mcosql_get_array_element_value_for_update(void* array, int index, type_t* type, void* value);
/* Get array body: copy the specified number of elements from the specified offset
to the buffer. This method can be used only for arrays of scalar types. */
mcosql_get_array_body(void* array, void* dst, int offs, int len);
/* Set array length */
mcosql_set_array_length(void* array, int length);
/* Set array element value */
mcosql_set_array_element_value(void* array, int index, type_t type, void* value);
/* Set array body: copy the specified number of elements from buffer to the array
using the specified offset. This method can be used only for arrays of scalar types. */
mcosql_set_array_body(void* array, void* src, int offs, int len);
以下代码片段展示了如何使用这些函数来处理一个数组(或向量)字段的示例:
void process_array(void * value)
{
unsigned int i, len = 0;
mcosql_get_array_length(value, &len);
for (i = 0; i < len; i++)
{
type_t inner_type;
void* inner_value;
mcosql_get_array_element_value(value, i, &inner_type, &inner_value);
/* Do what is needed with the array element */
}
}
对于与数据库中类型为 ref(对另一个数据库对象的引用)的字段相对应的结果集列:
/* Get referenced record (by actual memory address ‘ref’) */
mcosql_get_referenced_record(void* ref, record_t* record);
对于与数据库中结构体类型字段相对应的结果集列:
/* Get number of components in the structure */
mcosql_get_struct_size(void* s, int* size);
/* Get structure component value */
mcosql_get_struct_component_value(void* s, int index, type_t* type, void* value);
/* Get structure or array component of a structure for updates to its components or elements. */
mcosql_get_struct_component_value_for_update(void* s, int index, type_t* type, void* value);
/* Set structure component value */
mcosql_set_struct_component_value(void* s, int index, type_t* type, void* value);
以下代码片段展示了使用这些函数处理字段的一个示例:
void process_struct(void * value)
{
unsigned int i, len = 0;
mcosql_get_struct_size(value, &len);
for (i = 0; i < len; i++)
{
type_t inner_type;
void* inner_value;
mcosql_get_struct_component_value(value, i, &inner_type, &inner_value);
/* Do what is needed with the struct field */
}
}
对于与数据库中类型为 blob(二进制大对象)的字段相对应的结果集列:
/* Return the number of bytes available to be extracted.
NB: This is not the total size of the BLOB, it can be smaller than BLOB size.
For example, if the BLOB consists of several segments, it can be the segment size. */
mcosql_blob_available_size(void* blob, int* size);
/* Copy BLOB data to the specified buffer. This method copies up to buffer_size bytes
from the current position in the BLOB to the specified buffer. Then, the current
position is advanced by the number of bytes fetched. */
mcosql_blob_get_data(void* blob, void* buffer, int buffer_size, int* n_bytes);
/* Append new data to the BLOB. NB: Append is always performed at the end of the
BLOB and doesn't change the current position for the GET method. */
mcosql_blob_append_data(void const* blob, void* buffer, int size);
/* Reset the current position to the beginning of the BLOB */
mcosql_blob_reset(void* blob);