隐式获取ROWID¶
关于隐式获取ROWID¶
在神通数据库的每张表中都有一个隐藏列rowid,,rowid是一个bigint的唯一数值。rowid的值在插入数据时有数据库自动生成,在删除数据时销毁。ROWID 值有几个重要用途,它们是表中行的唯一标识符,是访问单行的最快方式。
在SELECT ... FOR UPDATE 语句中可以隐式获取ROWDID,通过设置,客户端程序可以获得每一行数据的rowid值,即使select sql语句中没有指定rowid作为查询列,但注意的是隐式获取rowid只针对select for update语句,其他语句不支持。
ACIDefineByPos的位置参数设置为零 (0)。 可以指定这些数据类型的变量来定义检索 ROWID 伪列值:
- SQLT_CHR (VARCHAR2)
- SQLT_VCS (VARCHAR)
- SQLT_STR (NULL-terminated string)
- SQLT_LVC (LONG VARCHAR)
- SQLT_AFC (CHAR)
- SQLT_RDD (ROWID descriptor)
SELECT ... FOR UPDATE 语句标识要更新的行,然后锁定结果集中的每一行。 当您希望根据行中的现有值进行更新时,这很有用。 在这种情况下,您必须确保其他用户不会更改该行。
当您指定字符缓冲区来存储 ROWID 的值时(例如,如果以 SQLT_STR 格式获取它),请分配足够的内存来存储 ROWID。
在使用隐式获取 ROWID 之前,必须在语句句柄上设置属性 ACI_ATTR_FETCH_ROWID,如下所示:
ACIAttrSet(stmthp, ACI_HTYPE_STMT, 0, 0 , ACI_ATTR_FETCH_ROWID, errhp);
使用 ACIDefineByPos 或 ACIDefineByPos2 作为位置 0,用于将一组数据同时提取到用户缓冲区中并同时获取它们各自的 ROWID。 它允许使用 SELECT....FOR UPDATE 语句获取 ROWID,即使 ROWID 不是 SELECT 查询中的列之一。如果每次只获取一行,也可以通过语句句柄的ACI_ATTR_ROWID属性获取。
如果使用ACI_ATTR_FETCH_ROWID属性并用 ACIDefineByPos 或 ACIDefineByPos2 去做定义,则不能使用语句句柄上的ACI_ATTR_ROWID属性获取ROWID。 反之亦然,对于特定的语句句柄,一次只能使用其中一个方法获得rowid
如果用语句句柄上的ACI_ATTR_ROWID 属性获取ROWID,但每次fetch获取多行,则通过ACI_ATTR_ROWID返回的是最后一条数据的rowid值。
通过SQLT_RDD类型的描述符定义获取rowd数据,必须用 ACIDescriptorAlloc 进行分配,使用完成后用 ACIDescriptorFree 进行释放,描述符类型为ACI_DTYPE_ROWID。
注解
ACI_ATTR_FETCH_ROWID设置必须是在 ACIStmtPrepare 或 ACIStmtPrepare2 后设置;ACI_ATTR_ROWID只能返回SQLT_RDD描述符,可通过ACIRowidToChar函数将rowid描述符转换为字符串,由于神通数据库的rowid其实是一个bigint,应用开发者可以将字符串转换为数值类型,但要确保数值的范围。
ACIRowidToChar返回的rowid字符串永远是单字节字符串,即使设置客户端为utf16字符集,返回的字符串也不是双字节的。
示例1:ACI_ATTR_FETCH_ROWID获取rowid¶
text sql[] = "select c1 from tb_test for update";
ACIStmt* stmt = NULL;
sword r = ACI_SUCCESS;
ACIDefine* define[2] = { NULL };
sb2 indp0[10] = { 0 };
sb2 indp1[10] = { 0 };
ub2 alep0[10] = { 0 };
ub2 alep1[10] = { 0 };
ub2 rcodep0[10] = { 0 };
ub2 rcodep1[10] = { 0 };
ACIRowid* rowid[10] = { NULL };
int def_c1[10] = { 0 };
r = ACIArrayDescriptorAlloc(env, (void**)&rowid[0], ACI_DTYPE_ROWID, sizeof(rowid) / sizeof(rowid[0]), 0, NULL);
r = ACIHandleAlloc(env, (void**)&stmt, ACI_HTYPE_STMT, 0, NULL);
r = ACIStmtPrepare(stmt, err, sql, strlen((const char*)sql), ACI_NTV_SYNTAX, ACI_DEFAULT);
{
/**
* ACI_ATTR_FETCH_ROWID 只用于 select for update行锁语句
* 必须进行行锁,否则set属性报错:ORA-24423: 无法设置 ROWID 属性 - ACI_ATTR_FETCH_ROWID
*/
r = ACIAttrSet(stmt, ACI_HTYPE_STMT, NULL, 0, ACI_ATTR_FETCH_ROWID, err);
}
r = ACIDefineByPos(stmt, &define[0], err, 0, (void*)&rowid[0], sizeof(ACIRowid*), SQLT_RDD, &indp0[0], &alep0[0], &rcodep0[0], ACI_DEFAULT);
r = ACIDefineByPos(stmt, &define[1], err, 1, &def_c1[0], sizeof(int), SQLT_INT, &indp1[0], &alep1[0], &rcodep1[0], ACI_DEFAULT);
r = ACIStmtExecute(svc, stmt, err, 10, 0, NULL, NULL, ACI_DEFAULT);
示例2:ACI_ATTR_ROWID获取rowid¶
text sql[] = "select c1 from tb_test for update";
ACIStmt* stmt = NULL;
ACIDefine* define = NULL;
sb2 indp[10] = { 0 };
ub2 alep[10] = { 0 };
ub2 rcodep[10] = { 0 };
int def_c1[10] = { 0 };
r = ACIHandleAlloc(env, (void**)&stmt, ACI_HTYPE_STMT, 0, NULL);
r = ACIStmtPrepare(stmt, err, sql, strlen((const char*)sql), ACI_NTV_SYNTAX, ACI_DEFAULT);
r = ACIDefineByPos(stmt, &define, err, 1, &def_c1[0], sizeof(int), SQLT_INT, &indp[0], &alep[0], &rcodep[0], ACI_DEFAULT);
r = ACIStmtExecute(svc, stmt, err, 0, 0, NULL, NULL, ACI_DEFAULT);
while (ACI_NO_DATA != (r = ACIStmtFetch2(stmt, err, 1, 0, ACI_FETCH_NEXT, ACI_DEFAULT)))
{
ACIRowid* rowid = NULL;
r = ACIDescriptorAlloc(env, (void**)&rowid, ACI_DTYPE_ROWID, 0, NULL);
/**
* 属性 ACI_ATTR_ROWID
* 该属性 也只能用于 select for update语句,该属性直接存储 ACIRowid结构
*/
ub4 size = 0;
r = ACIAttrGet(stmt, ACI_HTYPE_STMT, (void*)rowid, &size, ACI_ATTR_ROWID, err);
}
r = ACIHandleFree(stmt, ACI_HTYPE_STMT));