金仓数据库KingbaseES———DCI连接模块的处理过程
关键字:
DCI、连接建立、连接释放、人大金仓、KingbaseES
DCI连接配置
DCI连接数据库支持配置文件服务名的连接方式,通过设置数据库服务句柄、结合用户名、密码认证连接到服务器。一般情况下,sys_service.conf文件中的配置项包含:
host 数据库服务器的地址,包括域名、主机名、主机的 IP 地址等。
port 端口号
dbname 数据库名
DCILog 指定日志信息文件的保存路径。
DCILogLevel 指定日志级别。
UseDciDat数据库中的 timestamp 类型的处理方式。
AutoCommit 是否采用自动提交事务方式,默认是 1,表示采用自动提交模式;如果指定为 0,表示采用手动提交模式。
BatchInsertSize_Ext 批量 DML 扩展优化。
SSLMode SSL 加密连接的方式。
pqopt SSL 加密连接相关的从属配置。
同时支持以“IP:PORT:DBNAME”方式连接数据库,使用这种方式时,需要将配置文件sys_service.conf中的服务名改为“Default”,使配置将生效。如果在配置文件找不到“Default”服务名、或者环境变量找不到配置文件,则 sys_service.conf 文件中服务名为“Default”的配置将生效,即类Oracle的默认值模式。
AutoCommit=0
AutoCommitDDL=1
BatchInsertSize_Ext=1
Protocol=7.4-2
DCI应用程序有两套默认值,服务名映射方式连接数据库情况下AutoCommit=1、BatchInsertSize_Ext=0配置参数生效(自动提交),连接串形式连接数据库情况下类oracle模式生效。两套默认值的不同在于:原默认值中默认 AutoCommit=1,并且不配置 BatchInsertSize_Ext,即默认该配置为 0;类 Oracle 默认值则开启上述四个配置。
DCI支持的事务模式如表1所示。
表1 DCI支持的事务模式
序号 | 事务模式 | 事务项配置 | 事务场景 |
1 | 手动提交事务模式场景 | AutoCommit=0 | 服务名映射连接 |
2 | 自动提交事务模式场景 | AutoCommit=1 | 默认事务模式 1)服务名映射连接; 2)连接串模式sys_service.conf没有Default服务名 |
3 | 语句级事务回滚模式场景 | AutoCommit=0 Protocol=7.4-2 | 服务名映射连接 |
4 | DDL语句自动提交事务模式场景 | AutoCommit=0 AutoCommitDDL=1 | 服务名映射连接 |
6 | “Default”服务名模式场景 | 自定义模式 | 连接串形式连接 |
5 | 类oracle事务模式场景 | AutoCommit=0 Protocol=7.4-2 AutoCommitDDL=1 BatchInsertSize_Ext=1 | 默认事务模式
|
DCI连接建立
DCI连接数据库建立在成功初始化各项句柄的前提下,主要进行的工作是连接相关句柄的空间申请和域数据库建立连接,值得注意的是读写分离过程中主从连接建立与负载均衡策略。在DCI提供的接口中,连接建立仅通过DCISessionBegin( )实现,函数定义为:
sword DCISessionBegin(DCISvcCtx *svchp,
DCIError *errhp,
DCISession *usrhp,
ub4 credt,
ub4 mode)
DCISessionBegin( )内部的调用关系如图1所示。
图1 DCISessionBegin( )函数调用关系
- 执行ociret = GetConnInfo(svchp->pServer->dblink, usrhp);读取连接信息,若是采用读写分离,连接服务器集群(服务器数量>1),申请增加的连接句柄ConnectionClass
ret = KSAPI_AllocConnect(pSession->pEnv->henv, (HDBC *)&con);
KSAPI_AllocConnect
RETCODE KSQL_API KSAPI_AllocConnect(HENV henv, HDBC * phdbc)
在环境句柄下分配连接句柄conn。
在申请到从属服务器连接的空间之后,将其赋值给主连接(在句柄分配时已经完成配置)的下一个节点,将主连接current的配置参数拷贝到新申请的空间中,继续申请并配置下一个节点
current->nextConnection = con;
KSAPI_ConnectionCopy(con,current);
current = current->nextConnection;
KSAPI_ConnectionCopy
RETCODE KSQL_API
KSAPI_ConnectionCopy(HDBC destHdbc, const HDBC srcHdbc)
拷贝已有连接句柄的connInfo结构体参数到新的连接句柄,没有错误设置
调用GetConnInfo失败后执行
InternalSetError(errhp, SQL_HANDLE_DBC, svchp->pSession->hdbc, 65001, "Can not find sys_service.conf", "00000");
② 与服务器建立连接,涉及到ConnectionClass:
ret = KSAPI_DriverConnect(hdbc, NULL, connIn, (KSQLSMALLINT)strlen(connIn), connOut, 8192, &cbOut, KSQL_DRIVER_NOPROMPT);
KSAPI_DriverConnect
RETCODE
KSQL_API KSAPI_DriverConnect(HDBC hdbc, HWND hwnd,
const KSQLCHAR * szConnStrIn,
KSQLSMALLINT cbConnStrIn,
KSQLCHAR * szConnStrOut,
KSQLSMALLINT cbConnStrOutMax,
KSQLSMALLINT * pcbConnStrOut,
KSQLUSMALLINT fDriverCompletion)
错误设置:调用CC_set_error(conn, CONN_ERR_OPENDB_ERROR, "Connection string parse error", func);在ConnectionClass上设置错误,调用
retval = CC_connect(conn, salt);
执行真正的连接操作。
CC_connect
char CC_connect(ConnectionClass *conn, char *salt_para)
ODBC层的连接操作。内部调用ret = LIBPQ_CC_connect(conn, salt_para);建立连接:
- 首先初始化日志;
- 再调用retval = LIBPQ_connect(conn);建立连接并在连接句柄conn上设置错误信息:CC_set_error(conn, CONN_ERR_OPENDB_ERROR, emsg, func);该函数成功返回1,失败返回0或者-1;
- 调用res = CC_send_query(conn, setsql, NULL, READ_ONLY_QUERY, NULL);获取结果集,内部调用CC_send_query_append,通过CC_set_error在连接句柄conn上设置错误信息。
- 对结果集res进行处理,不设置错误信息。
调用CC_set_translation对win32平台进行转换处理,并设置错误信息。该函数不接受返回值,故而执行出错后不做处理。
调用CC_send_settings,并在连接句柄conn上进行错误设置:
- 调用KSAPI_AllocStmt申请临时语句句柄;
- 调用KSAPI_ExecDirect执行相应的配置语句,ODBC层的语句执行流程,在临时语句句柄上进行错误消息设置;
- 调用KSAPI_FreeStmt释放临时语句句柄。
后续对于连接的处理:CC_lookup_lo(conn)、CC_determine_locale_encoding(conn)、CC_get_mode(conn)、CC_get_supportNewInterval(conn)、CC_get_extend_typeoid(conn)、CC_get_supportNewRowid(conn)、CC_send_client_encoding(conn, conn->client_encoding ? conn->client_encoding : conn->locale_encoding)等都会对连接句柄conn设置错误码。
③ 连接申请之后,需要设置相应的属性
ret = KSAPI_SetConnectAttr(hdbc, KSQL_ATTR_AUTOCOMMIT, (PTR) KSQL_AUTOCOMMIT_ON, KSQL_IS_INTEGER);
KSAPI_SetConnectAttr
RETCODE KSQL_API KSAPI_SetConnectAttr(HDBC ConnectionHandle,
KSQLINTEGER Attribute, PTR Value,
KSQLINTEGER StringLength)
根据是否自动提交设置连接句柄的各种属性,若是不支持的属性,调用
CC_set_error(conn, CONN_ERR_OPTION_NOT_FOR_THE_DRIVER, msg, func);
在ConnectionClass上设置错误信息
在KSAPI_SetConnectAttr内部,调用KSAPI_SetConnectOption设置操作属性:
KSAPI_SetConnectOption
RETCODE KSQL_API KSAPI_SetConnectOption(HDBC hdbc,
KSQLUSMALLINT fOption,
KSQLULEN vParam)
调用
CC_set_error(conn, CONN_ERR_TRANSACT_IN_PROGRES, "Cannot switch isolation level while a transaction is in progress", func);
在ConnectionClass上设置错误信息
在KSAPI_SetConnectOption内部,调用CC_set_transact,内部在ConnectionClass设置错误消息:
CC_set_error(conn, CONN_ERR_EXEC_ERROR, "ISOLATION change request to the server error", __FUNCTION__);
④ 如果当前建立连接的IP序列号为0,调用KSAPI_DriverInit取消连接:
ret = KSAPI_DriverInit(hdbc, NULL, connIn, (KSQLSMALLINT)strlen(connIn), connOut, 8192, &cbOut, KSQL_DRIVER_NOPROMPT);
KSAPI_DriverInit
RETCODE KSQL_API
KSAPI_DriverInit(HDBC hdbc, HWND hwnd, const KSQLCHAR * szConnStrIn,
KSQLSMALLINT cbConnStrIn, KSQLCHAR * szConnStrOut,
KSQLSMALLINT cbConnStrOutMax,
KSQLSMALLINT * pcbConnStrOut,
KSQLUSMALLINT fDriverCompletion)
通过以下函数设置错误消息:
CC_set_error(conn, CONN_ERR_OPENDB_ERROR, "Connection string parse error", func);
⑤ 如果所有连接都未建立成功,调用下面函数获取错误信息,获取EnvironmentClass 、ConnectionClass、StatementClass、DescriptorClass四类底层错误,并设置到errhp句柄上:
ret = KSAPI_GetDiagRec(KSQL_HANDLE_DBC, usrhp->hdbc, 1, sqlstate, (KSQLINTEGER *) &error_code, msg, 256, NULL);
KSAPI_GetDiagRec
RETCODE KSQL_API
KSAPI_GetDiagRec(KSQLSMALLINT HandleType, KSQLHANDLE Handle,
KSQLSMALLINT RecNumber, KSQLCHAR *Sqlstate,
KSQLINTEGER *NativeError, KSQLCHAR *MessageText,
KSQLSMALLINT BufferLength, KSQLSMALLINT *TextLength)
内部涉及KSAPI_EnvError(environ.c)、KSAPI_ConnectError(environ.c)、KSAPI_StmtError(statement.c)、KSAPI_DescError(descriptor.c)的错误消息获取。
DCI连接释放
在程序执行结束后,需要断开与服务器的连接,释放会话资源。在DCI中,主要通过接口DCISessionEnd( )实现,函数定义如下所示:
sword DCISessionEnd(DCISvcCtx *svchp, DCIError *errhp,
DCISession *usrhp, ub4 mode)
程序运行结束后,结束会话,释放申请的ODBC连接句柄和语句句柄。错误设置:包含错误句柄errhp,可以向下传入。
释放连接时调用KSAPI_Disconnect(hdbc);执行时设置错误。
KSAPI_Disconnect
RETCODE KSQL_API KSAPI_Disconnect(HDBC hdbc)
断开与数据库服务器的连接,若是当前连接有事务执行,设置错误:
CC_set_error(conn, CONN_ERR_IN_USE, "A transaction is currently being executed.", func);
内部调用CC_cleanup执行操作:
char CC_cleanup(ConnectionClass *conn, BOOL keepCommunication)
CC_cleanup内部释放当前连接conn下的描述句柄时调用
void DC_Destructor(DescriptorClass *desc)
内部依次释放conn->num_descs 个DescriptorClass的错误消息__error_message,错误句柄ER_Destructor(deschd->kserror)。




