1.OCIBindByName和OCIBindByPos
OCI提供了两种方法来绑定参数到SQL语句中的占位符:OCIBindByPos和OCIBindByName。
1.OCIBindByName函数原型:
OCIBindByName(
OCIStmt *stmtp,
OCIBind **bindpp,
OCIError *errhp,
const text *placeholder,
sb4 placeh_len,
dvoid *valuep,
sb4 value_sz,
ub2 dty,
dvoid *indp,
ub2 *alenp,
ub2 *rcodep,
ub4 maxarr_len,
ub4 *curelep,
ub4 mode
)
- 通过占位符的名称绑定参数到SQL语句中的占位符位置。
- 占位符的名称由参数"placeholder"指定。
- 参数"placeh_len"指定占位符的名称长度。
- 其他参数的含义:
- valuep: 指向数据的指针。
- value_sz: 数据的大小。
- dty: 数据的类型。
- indp: 指示数据的指针,用于处理空值或者处理绑定变量为数组时的偏移量。
- alenp: 数据的实际长度。
- rcodep: 返回代码的指针。
- maxarr_len: 绑定变量为数组时,表示数组的最大长度。
- curelep: 绑定变量为数组时,表示已填充的数组元素个数。
- mode: 绑定模式。
2.OCIBindByPos函数原型:
OCIBindByPos(
OCIStmt *stmtp,
OCIBind **bindpp,
OCIError *errhp,
ub4 position,
dvoid *valuep,
sb4 value_sz,
ub2 dty,
dvoid *indp,
ub2 *alenp,
ub2 *rcodep,
ub4 maxarr_len,
ub4 *curelep,
ub4 mode
)
- 通过占位符的位置绑定参数到SQL语句中的占位符位置。
- 参数"position"指定了占位符的位置,从1开始计数。
- 其他参数的含义与OCIBindByName类似。
这两个函数的作用是将应用程序中的变量或者数据与SQL语句中的占位符相关联。OCIBindByName通过占位符的名称进行绑定,而OCIBindByPos通过占位符的位置进行绑定。这两种方法可以根据具体的需求来选择使用。
3.OCIBindByName 示例:
OCIStmt *stmt;
OCIBind *bind;
int id = 100;
// 准备语句
OCIStmtPrepare(stmt, err, (text *)"SELECT name FROM employees
WHERE emp_id = :empid", -1, OCI_NTV_SYNTAX, OCI_DEFAULT);
// 通过名称绑定变量
OCIBindByName(stmt, &bind, err, (text *)":empid", -1, &id,
sizeof(int), SQLT_INT, NULL, NULL, NULL, 0, NULL, OCI_DEFAULT);
// 执行语句
OCIStmtExecute(svchp, stmt, err, 1, 0, NULL, NULL, OCI_DEFAULT);
// 获取结果
char name[50];
OCIStmtFetch2(stmt, err, 1, OCI_FETCH_NEXT, 0, OCI_DEFAULT);
// 从绑定变量中取值
OCIString *result;
OCIAttrGet(bind, OCI_HTYPE_BIND, &result, NULL, OCI_ATTR_VALUE, err);
printf("Name: %s\n", OCIStringPtr(result));
说明:
- 以上示例通过名称绑定了一个变量
:empid
,并将其值设置为100。 - 语句准备阶段,使用了一个带有参数的SELECT语句,其中的
:empid
就是绑定的变量。 - 在执行语句后,通过OCIStmtFetch2函数获取结果集的下一行。
- 使用OCIAttrGet函数从绑定变量中获取值,并以字符串形式打印输出。
4.OCIBindByPos 示例:
OCIStmt *stmt;
OCIBind *bind;
int id = 100;
// 准备语句
OCIStmtPrepare(stmt, err, (text *)"SELECT name FROM employees
WHERE emp_id = ?", -1, OCI_NTV_SYNTAX, OCI_DEFAULT);
// 通过位置绑定变量
OCIBindByPos(stmt, &bind, err, 1, &id, sizeof(int), SQLT_INT,
NULL, NULL, NULL, 0, NULL, OCI_DEFAULT);
// 执行语句
OCIStmtExecute(svchp, stmt, err, 1, 0, NULL, NULL, OCI_DEFAULT);
// 获取结果
char name[50];
OCIStmtFetch2(stmt, err, 1, OCI_FETCH_NEXT, 0, OCI_DEFAULT);
// 从绑定变量中取值
OCIString *result;
OCIAttrGet(bind, OCI_HTYPE_BIND, &result, NULL, OCI_ATTR_VALUE, err);
printf("Name: %s\n", OCIStringPtr(result));
说明:
- 以上示例通过位置绑定了一个变量,将其值设置为100。
- 语句准备阶段,使用了一个带有参数的SELECT语句,其中的?表示绑定变量的位置。
- 在执行语句后,通过OCIStmtFetch2函数获取结果集的下一行。
- 使用OCIAttrGet函数从绑定变量中获取值,并以字符串形式打印输出。
Note:
1.无论使用OCIBindByName还是OCIBindByPos,结果都是一样的。关键区别在于绑定变量的方式:OCIBindByName是通过名称绑定变量,而OCIBindByPos是通过位置绑定变量。
2.冒号后+名字和问号(:empid 或者 ?)都可以表示占位符。
2.OCI连接Oracle数据库的流程
#include <stdio.h>
#include <oci.h>
void check_error(OCIError *err, sword status) {
text error_msg[512];
sb4 error_code;
if (status != OCI_SUCCESS) {
OCIErrorGet(err, 1, NULL, &error_code, error_msg, sizeof(error_msg), OCI_HTYPE_ERROR);
printf("Error: %d - %s\n", error_code, error_msg);
exit(1);
}
}
int main() {
OCIEnv *env;
OCIError *err;
OCIServer *srv;
OCISession *ses;
OCISvcCtx *svc;
sword status;
// 初始化OCI环境
status = OCIEnvCreate(&env, OCI_THREADED | OCI_OBJECT, NULL, NULL, NULL, NULL, 0, NULL);
check_error(err, status);
// 分配错误句柄
status = OCIHandleAlloc(env, (dvoid **)&err, OCI_HTYPE_ERROR, 0, NULL);
check_error(err, status);
// 初始化服务器句柄
status = OCIHandleAlloc(env, (dvoid **)&srv, OCI_HTYPE_SERVER, 0, NULL);
check_error(err, status);
// 初始化会话句柄
status = OCIHandleAlloc(env, (dvoid **)&ses, OCI_HTYPE_SESSION, 0, NULL);
check_error(err, status);
// 创建服务器上下文
status = OCIServerAttach(srv, err, (text *)"<db_name>", strlen("<db_name>"), OCI_DEFAULT);
check_error(err, status);
// 设置会话句柄的服务器属性
status = OCIAttrSet(ses, OCI_HTYPE_SESSION, srv, 0, OCI_ATTR_SERVER, err);
check_error(err, status);
// 设置会话句柄的用户名和密码属性
status = OCIAttrSet(ses, OCI_HTYPE_SESSION, (text *)"<username>", strlen("<username>"), OCI_ATTR_USERNAME, err);
check_error(err, status);
status = OCIAttrSet(ses, OCI_HTYPE_SESSION, (text *)"<password>", strlen("<password>"), OCI_ATTR_PASSWORD, err);
check_error(err, status);
// 创建服务器上下文句柄
status = OCIHandleAlloc(env, (dvoid **)&svc, OCI_HTYPE_SVCCTX, 0, NULL);
check_error(err, status);
// 设置服务器上下文句柄的会话属性
status = OCIAttrSet(svc, OCI_HTYPE_SVCCTX, ses, 0, OCI_ATTR_SESSION, err);
check_error(err, status);
// 开始会话
status = OCISessionBegin(svc, err, ses, OCI_CRED_RDBMS, OCI_DEFAULT);
check_error(err, status);
printf("Connected to Oracle database\n");
// 关闭会话
status = OCISessionEnd(svc, err, ses, OCI_DEFAULT);
check_error(err, status);
// 断开服务器连接
status = OCIServerDetach(srv, err, OCI_DEFAULT);
check_error(err, status);
// 释放句柄和环境
OCIHandleFree(svc, OCI_HTYPE_SVCCTX);
OCIHandleFree(ses, OCI_HTYPE_SESSION);
OCIHandleFree(srv, OCI_HTYPE_SERVER);
OCIHandleFree(err, OCI_HTYPE_ERROR);
OCIHandleFree(env, OCI_HTYPE_ENV);
return 0;
}
3.指示器变量
指示器变量是用来处理数据库 NULL 值的变量。当执行 SELECT
或者 FETCH
语句时,如果不使用指示器变量并且列返回的值为 NULL 时,会显示错误信息。指示器变量必须采用 short
类型定义,并且指示器变量必须跟在宿主变量后面。
指示器变量的语法如下所示:
:host_variable [INDICATOR] :indicator_variable
在使用指示器变量后,可以检测出返回的列是否为 NULL:
-
当指示器变量返回 -1 时,表示数据库返回 NULL 值。
-
当指示器变量返回 0 时,表示列值被赋给了输出宿主变量。
-
当指示器变量返回的值大于 0 时,表示将被截断列值付给了输出宿主变量,并且指示器变量存放着数据库列值的实际长度。
-
当指示器变量返回值为 -2 时,表示被截断列值付给了输出宿主变量,但是实际长度不能确定。