快速入门
📄字数 5.8K
👁️阅读量 加载中...
此章节将使用最简单的代码展示如何使用 XuguNCI 向虚谷数据库插入和查询数据,以及展示如何通过 XuguNCI 操作数值类型、字符类型和结构体类型的字段以实现数值的插入和查询。用户阅读此章节可快速了解 XuguNCI 的使用方法,用户可编译运行本章节后附带的示例程序并查看执行效果,可基于附带的示例程序改写符合用户特定需求的程序代码。
句柄类型
在 NCI 中,与数据库进行交互所需要使用的句柄有:
- NCIEnv:环境句柄
- NCIError:错误句柄
- NCIServer:服务器句柄
- NCISvcCtx:上下文句柄
- NCISession:会话句柄
- NCIStmt:语句句柄
创建句柄
环境句柄使用 NCIEnvCreate 创建,其他句柄以环境句柄作为父句柄使用 NCIHandleAlloc 创建。句柄的销毁则统一由 NCIHandleFree 完成。
NCIEnvCreate 的原型为:
C
sword NCIEnvCreate (NCIEnv **envp, ub4 mode, void *ctxp,
void *(*malocfp)(void *ctxp, size_t size),
void *(*ralocfp)(void *ctxp, void *memptr, size_t newsize),
void (*mfreefp)(void *ctxp, void *memptr),
size_t xtramem_sz, void **usrmempp);
一般情况下,不需要指定内存分配相关的函数,因此只需要关注前两个参数,第一个为环境句柄指针的地址,第二个固定传 NCI_DEFAULT,剩下的指针类型参数全部传入 NULL,数值类型传入 0 即可。
NCIHandleAlloc 的原型为:
C
sword NCIHandleAlloc(const void *parenth, void **hndlpp, const ub4 type,
const size_t xtramem_sz, void **usrmempp);
第一个参数为环境句柄,第二个参数为句柄指针的地址,第三个参数为待创建句柄的类型,第四个参数传入 0,第五个参数传入 NULL。
句柄与句柄类型的关系如下:
- NCIEnv:NCI_HTYPE_ENV
- NCIError:NCI_HTYPE_ERROR
- NCIServer:NCI_HTYPE_SERVER
- NCISvcCtx:NCI_HTYPE_SVCCTX
- NCISession:NCI_HTYPE_SESSION
- NCIStmt:NCI_HTYPE_STMT
C
NCIEnv* env;
NCIError* err;
NCIServer* server;
NCISvcCtx* ctx;
NCISession* session;
NCIStmt* stmt;
NCIEnvCreate(&env, NCI_DEFAULT, NULL, NULL, NULL, NULL, 0, NULL);
NCIHandleAlloc(env, &err, NCI_HTYPE_ERROR, 0, NULL);
NCIHandleAlloc(env, &server, NCI_HTYPE_SERVER, 0, NULL);
NCIHandleAlloc(env, &ctx, NCI_HTYPE_SVCCTX, 0, NULL);
NCIHandleAlloc(env, &session, NCI_HTYPE_SESSION, 0, NULL);
NCIHandleAlloc(env, &stmt, NCI_HTYPE_STMT, 0, NULL);
为句柄设置属性
服务器句柄需使用 NCIServerAttach 通过连接串设置连接信息,连接串格式为:host:port/database。接口的原型为:
C
sword NCIServerAttach(NCIServer *srvhp, NCIError *errhp, const OraText *dblink, sb4 dblink_len, ub4 mode);
会话句柄需使用 NCIAttrSet 设置用户名和密码。服务器句柄和会话句柄需使用 NCIAttrSet 设置进上下文句柄。接口的原型为:
C
sword NCIAttrSet(void *trgthndlp, ub4 trghndltyp, void *attributep, ub4 size, ub4 attrtype, NCIError *errhp);
第一二个参数为句柄和句柄类型,第三四个参数为属性值及其大小,第五个参数为属性值类型,此章节用到的属性值类型有:
- NCI_ATTR_USERNAME
- NCI_ATTR_PASSWORD
- NCI_ATTR_SERVER
- NCI_ATTR_SESSION
C
const char* dblink = "127.0.0.1:5138/SYSTEM";
NCIServerAttach(server, err, dblink, strlen(dblink), NCI_DEFAULT);
NCIAttrSet(session, NCI_HTYPE_SESSION, user, strlen(user), NCI_ATTR_USERNAME, err);
NCIAttrSet(session, NCI_HTYPE_SESSION, pwd, strlen(pwd), NCI_ATTR_PASSWORD, err);
NCIAttrSet(ctx, NCI_HTYPE_SVCCTX, server, 0, NCI_ATTR_SERVER, err);
NCIAttrSet(ctx, NCI_HTYPE_SVCCTX, session, 0, NCI_ATTR_SESSION, err);
登录数据库
将连接信息和登录信息正确设置进句柄后,即可登录数据库。登录数据库的接口原型为:
C
sword NCISessionBegin(NCISvcCtx *svchp, NCIError *errhp, NCISession *usrhp, ub4 credt, ub4 mode);
前三个参数均为句柄,后两个参数在 XuguNCI 中无实际用途。
C
ret = NCISessionBegin(ctx, err, session, NCI_CRED_RDBMS, NCI_DEFAULT);
if (ret != NCI_SUCCESS) {
// get error info
}
使用 NCISessionBegin 接口登录数据库前置过程繁琐,NCI 提供了较为方便的 NCILogon。NCILogon 对登录数据库的前置操作进行了封装,大幅简化了登录的流程。其原型为:
C
sword NCILogon(NCIEnv *envhp, NCIError *errhp, NCISvcCtx **svchp,
const OraText *username, ub4 uname_len,
const OraText *password, ub4 passwd_len,
const OraText *dbname, ub4 dbname_len);
使用此接口不再需要创建服务器句柄和会话句柄,参数 dbname 为连接串。
执行 SQL 语句
在 NCI 中,执行所有 SQL 语句均需进行 prepare 操作。若执行查询语句,需在调用 NCIStmtPrepare 之后且在调用 NCIStmtExecute 之前进行 NCIDefineByPos 操作。若语句中带有参数,参数绑定也需在 NCIStmtPrepare 和 NCIStmtExecute 之间进行。
NCIStmtPrepare 原型为:
C
sword NCIStmtPrepare(NCIStmt *stmtp, NCIError *errhp, const OraText *stmt,
ub4 stmt_len, ub4 language, ub4 mode);
其中第一个参数为语句句柄,第二个参数为错误句柄,第三个参数为 SQL 语句,第四个参数为 SQL 语句的长度,最后两个参数未使用。
NCIStmtExecute 原型为:
C
sword NCIStmtExecute(NCISvcCtx *svchp, NCIStmt *stmtp, NCIError *errhp,
ub4 iters, ub4 rowoff, const NCISnapshot *snap_in,
NCISnapshot *snap_out, ub4 mode);
其中前三个参数为句柄,第四个参数的值取决于所执行的语句,若为 DDL 或 DML,其值传入 1 即可,若为 DQL,其值传入 0 即可。剩余参数均未使用。
C
const char* sql = "SELECT id FROM tab_test";
NCIStmtPrepare(stmt, err, sql, strlen(sql), NCI_NTV_SYNTAX, NCI_DEFAULT);
NCIDefine* def;
int id;
NCIDefineByPos(stmt, &def, err, 1, &id, 4, SQLT_INT, NULL, NULL, NULL, NCI_DEFAULT);
NCIStmtExecute(ctx, stmt, err, 0, 0, NULL, NULL, NCI_DEFAULT);
while ((ret = NCIStmtFetch(stmt, err, 1, NCI_FETCH_NEXT, NCI_DEFAULT)) == NCI_SUCCESS) {
printf("%d\n", id);
}
销毁句柄
每个句柄均存储相关的信息,因此句柄使用完毕后需将其销毁以释放内存,其接口原型为:
C
sword NCIHandleFree(void *hndlp, const ub4 type);
其中第一个参数为句柄,第二个参数为句柄类型。
C
NCIHandleFree(stmt, NCI_HTYPE_STMT);
NCIHandleFree(session, NCI_HTYPE_SESSION);
NCIHandleFree(ctx, NCI_HTYPE_SVCCTX);
NCIHandleFree(server, NCI_HTYPE_SERVER);
NCIHandleFree(err, NCI_HTYPE_ERROR);
NCIHandleFree(env, NCI_HTYPE_ENV);
完整代码
此示例依赖的表结构为:
SQL
CREATE TABLE tab_test (
id INT,
name VARCHAR(20),
created DATE
);
C
//main.c
#include <stdio.h>
#include <string.h>
#include "nci.h"
void printError(NCIError* err)
{
sb4 errCode;
char errMsg[128];
NCIErrorGet(err, 1, NULL, &errCode, errMsg, 128, NCI_HTYPE_ERROR);
printf("[%d]%s\n", errCode, errMsg);
}
void createTable(NCISvcCtx* ctx, NCIStmt* stmt, NCIError* err)
{
sword ret;
const char* sql = "CREATE TABLE tab_test (id INT, name VARCHAR(20), created DATE)";
ret = NCIStmtPrepare(stmt, err, sql, strlen(sql), NCI_NTV_SYNTAX, NCI_DEFAULT);
if (ret != NCI_SUCCESS) printError(err);
ret = NCIStmtExecute(ctx, stmt, err, 1, 0, NULL, NULL, NCI_DEFAULT);
if (ret != NCI_SUCCESS) printError(err);
}
void insert(NCISvcCtx* ctx, NCIStmt* stmt, NCIError* err)
{
sword ret;
const char* sql = "INSERT INTO tab_test (id, name, created) VALUES(:id, :name, :created)";
NCIStmtPrepare(stmt, err, sql, strlen(sql), NCI_NTV_SYNTAX, NCI_DEFAULT);
NCIBind* bind[3];
int id = 1;
const char* name = "Tom";
NCIDate created = { 2000,1,1 };
NCIBindByName(stmt, &bind[0], err, "id", 2, &id, 4, SQLT_INT, NULL, NULL, NULL, 0, NULL, NCI_DEFAULT);
NCIBindByName(stmt, &bind[1], err, "name", 4, name, sizeof(name), SQLT_STR, NULL, NULL, NULL, 0, NULL, NCI_DEFAULT);
NCIBindByName(stmt, &bind[2], err, "created", 7, &created, sizeof(created), SQLT_ODT, NULL, NULL, NULL, 0, NULL, NCI_DEFAULT);
ret = NCIStmtExecute(ctx, stmt, err, 1, 0, NULL, NULL, NCI_DEFAULT);
if (ret != NCI_SUCCESS) printError(err);
}
void query(NCISvcCtx* ctx, NCIStmt* stmt, NCIError* err)
{
sword ret;
const char* sql = "SELECT id, name, created FROM tab_test WHERE id = :id";
ret = NCIStmtPrepare(stmt, err, sql, strlen(sql), NCI_NTV_SYNTAX, NCI_DEFAULT);
int id = 1;
char name[20];
NCIDate created;
NCIBind* bind;
NCIBindByName(stmt, &bind, err, "id", 2, &id, 4, SQLT_INT, NULL, NULL, NULL, 0, NULL, NCI_DEFAULT);
NCIDefine* def[3];
NCIDefineByPos(stmt, &def[0], err, 1, &id, 4, SQLT_INT, NULL, NULL, NULL, NCI_DEFAULT);
NCIDefineByPos(stmt, &def[1], err, 2, name, sizeof(name), SQLT_CHR, NULL, NULL, NULL, NCI_DEFAULT);
NCIDefineByPos(stmt, &def[2], err, 3, &created, sizeof(created), SQLT_ODT, NULL, NULL, NULL, NCI_DEFAULT);
ret = NCIStmtExecute(ctx, stmt, err, 0, 0, NULL, NULL, NCI_DEFAULT);
if (ret != NCI_SUCCESS) printError(err);
while ((ret = NCIStmtFetch(stmt, err, 1, NCI_FETCH_NEXT, NCI_DEFAULT)) == NCI_SUCCESS)
{
printf("%d, %s, %d-%02d-%02d\n", id, name, created.NCIDateYYYY, created.NCIDateMM, created.NCIDateDD);
}
}
int main()
{
NCIEnv* env;
NCIError* err;
NCISvcCtx* ctx;
NCIStmt* stmt;
sword ret;
NCIEnvCreate(&env, NCI_DEFAULT, NULL, NULL, NULL, NULL, 0, NULL);
NCIHandleAlloc(env, &err, NCI_HTYPE_ERROR, 0, NULL);
const char* user = "SYSDBA";
const char* pwd = "SYSDBA";
const char* db = "127.0.0.1:5138/SYSTEM";
ret = NCILogon(env, err, &ctx, user, strlen(user), pwd, strlen(pwd), db, strlen(db));
if (ret != NCI_SUCCESS)
{
printError(err);
goto _end;
}
NCIHandleAlloc(env, &stmt, NCI_HTYPE_STMT, 0, NULL);
createTable(ctx, stmt, err);
insert(ctx, stmt, err);
query(ctx, stmt, err);
NCIHandleFree(stmt, NCI_HTYPE_STMT);
NCILogoff(ctx, err);
_end:
NCIHandleFree(ctx, NCI_HTYPE_SVCCTX);
NCIHandleFree(err, NCI_HTYPE_ERROR);
NCIHandleFree(env, NCI_HTYPE_ENV);
return 0;
}