日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

Oracle调用接口(OCI)源码剖析(2):执行SQL语句并获取结果

發布時間:2025/3/20 数据库 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Oracle调用接口(OCI)源码剖析(2):执行SQL语句并获取结果 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

概述
接著上一篇文章《Oracle調用接口(OCI)源碼剖析(1):創建數據庫連接》,我們繼續對OCI中執行SQL語句并獲取結果的源碼進行剖析。該操作主要是由兩個函數完成的:CDbExecSql和CDbFetch,其中CDbExecSql函數用于執行普通SQL語句,CDbFetch函數用于獲取數據庫的返回結果。

下面對這兩個函數的源碼進行分析。

OCI中執行SQL語句并獲取結果的源碼剖析

1.執行普通SQL語句的操作
在OCI中,執行普通SQL語句的操作是由CDbExecSql函數實現的,其代碼如下:

INT32 CDbExecSql(void *pHandle, INT8 *pSQL) {CDb *hDb = (CDb *)pHandle;CDbRecordset *pRec = NULL;OCIHDBC hdbc;sword rc = (sword)0;INT32 row_num = 0;if ((NULL == hDb) || (NULL == hDb->hdbc) || (NULL == hDb->hRec)){return OCI_ERROR;}hdbc = hDb->hdbc;pRec = hDb->hRec;/* 初始化結果集行數據Buf */memset((void *)pRec, 0, sizeof(CDbRecordset));/* 申請語句句柄 */rc = OCIHandleAlloc((dvoid *)hdbc->envhp, (dvoid**)&hdbc->stmthp, (ub4)OCI_HTYPE_STMT, (size_t)0, (dvoid **)0);if (RETCODE_IS_FAILURE(rc)){DoDbErrProc(hdbc->errhp, rc,"OCIHandleAlloc[OCI_HTYPE_STMT]");return OCI_ERROR;}/* 準備執行數據庫操作 */rc = DoDbSQLExecute(hDb, (text *)pSQL);if (RETCODE_IS_FAILURE(rc)){/************************************************* 如果語句是事務,則以下語句可保證不鎖表; ** 如果不是事務,也無關大局 *************************************************/if (OCI_STMT_SELECT != pRec->sqltype){OCITransRollback(hdbc->svchp, hdbc->errhp, (ub4)0);}/* 需要釋放stmt句柄 */DoStmtFree(hdbc->stmthp);return OCI_ERROR;}/* 對于非Select操作,直接返回 */if (OCI_STMT_SELECT != pRec->sqltype){/* 獲取受delete insert update所影響的列數 */rc = OCIAttrGet((dvoid *)hdbc->stmthp, (ub4)OCI_HTYPE_STMT, (dvoid *)&row_num,(ub4 *)0, OCI_ATTR_ROW_COUNT,hdbc->errhp);if (RETCODE_IS_FAILURE(rc)){row_num = OCI_ERROR;}/* 需要釋放stmt句柄 */DoStmtFree(hdbc->stmthp);if ( row_num == OCI_ERROR ){return C_OS_FAIL;}return C_OS_SUCCESS;}/* 定義結果集 */rc = DoDbDefine(hDb);if ((OCI_ERROR == rc) || (0 == rc)){rc = DoDbErrProc(hdbc->errhp, rc, "DoDbDefine");/* 需要釋放stmt句柄 */DoStmtFree(hdbc->stmthp);return rc;}return OCI_SUCCESS; }

從該函數的代碼實現中,我們可以看到:
1)執行普通SQL語句包括這幾步主要操作:第一步,申請語句句柄;第二步,執行數據庫操作;第三步,對于非Select操作直接返回,對于Select操作定義結果集。

2)申請語句句柄操作是由OCIHandleAlloc函數實現的,它是OCI底層自帶的函數。

3)執行數據庫操作是由DoDbSQLExecute函數實現的,該函數主要執行這幾步操作:第一步,執行OCIStmtPrepare函數準備SQL語句;第二步,執行OCIAttrGet函數獲取數據庫操作類型;第三步,執行OCIStmtExecute函數進行具體的數據庫操作。

4)定義結果集操作是由DoDbDefine函數實現的,該函數主要執行這幾步操作:第一步,執行OCIAttrGet函數提取數據庫操作返回列的列數;第二步,執行OCIParamGet函數在語句句柄中指定參數描述符;第三步,執行OCIAttrGet函數獲得返回結果集列數據類型;第四步,執行OCIAttrGet函數獲得返回結果集列名稱;第五步,執行OCIDefineByPos函數定義輸出變量。

2.獲取數據庫的返回結果的操作
在OCI中,獲取數據庫的返回結果的操作是由CDbFetch函數實現的,其代碼如下:

INT32 CDbFetch(void *pHandle, INT8 *pData,INT32 maxlen) {CDb *hDb = (CDb*)pHandle;CDbRecordset *pRec = NULL;OCIHDBC hdbc;sword rc =(sword)0;INT32 row_num = 0, iLoop, pos = 0;if ((NULL == hDb) || (NULL == hDb->hdbc) || (NULL == hDb->hRec)){return OCI_ERROR;}hdbc = hDb->hdbc;pRec = hDb->hRec;if ((NULL == hdbc->stmthp) || (NULL == hdbc->errhp)){return OCI_ERROR;}/* 獲取結果數據 */memset((void *)pData, 0, maxlen);memset(pRec->pRecordBuf, 0, CDB_MAX_COL_NUM * CDB_MAX_COL_WIDTH);rc = OCIStmtFetch(hdbc->stmthp, hdbc->errhp, 1, OCI_FETCH_NEXT, OCI_DEFAULT);if (OCI_NO_DATA == rc){DoStmtFree(hdbc->stmthp);return CDB_FETCH_NO_DATA;}rc = DoDbErrProc(hdbc->errhp, rc, "OCIStmtFetch");if ((OCI_SUCCESS != rc) && (OCI_SUCCESS_WITH_INFO != rc)){/* 需要釋放stmt句柄 */DoStmtFree(hdbc->stmthp);return OCI_ERROR;}/* 向pData填充結果集數據 */for (iLoop = 0; iLoop < pRec->colCount; iLoop++){int len;/* 清除尾部空格 */len = pRec->pColWidth[iLoop];switch (pRec->pColType[iLoop]){case SQLT_AFC:case SQLT_AVC:case SQLT_CHR:case SQLT_STR:len = DoDbrTrim(pRec->pRecordBuf[iLoop],sizeof(pRec->pRecordBuf[iLoop]));break;default:break;}/* 注意:如果長度不夠,返回值也是成功的 */if (pos + pRec->pColWidth[iLoop] > maxlen){break;}/* 拷貝實際長度數據 */memcpy((void *)(pData + pos), (const void *)pRec->pRecordBuf[iLoop], len);/* 偏轉定義長度 */pos += pRec->pColWidth[iLoop];}return OCI_SUCCESS; }

從該函數的代碼實現中,我們可以看到:
1)該函數主要完成將CDbExecSql函數執行SQL語句之后的結果拷貝到輸出緩存(pData)的操作。

2)在獲取結果數據之前,先用OCIStmtFetch函數來提取固定數目的記錄,同時也可判斷數據庫中是否有結果數據返回,如果沒有,則不執行后續操作。

3)注意函數中的for循環,它將數據庫返回的結果按照列的順序依次拷貝到輸出緩存中。其中,數據庫返回數據的列數是pRec->colCount,每列寬度存放在pRec->pColWidth[CDB_MAX_COL_NUM]數組中,每列的具體內容存放在pRec->pRecordBuf[CDB_MAX_COL_NUM][CDB_MAX_COL_WIDTH]二維數組中。

執行SQL語句并獲取結果的CDbExecSql和CDbFetch函數調用

CDbExecSql和CDbFetch函數調用要在獲取了數據庫的連接之后,也就是說,要連上數據庫之后才能獲取結果。

CDbExecSql和CDbFetch函數調用的示例代碼如下:

INT32 main(void) {INT8 szDBServerName[50] = {0};INT8 szDBName[50] = {0};INT8 szDBUser[50] = {0};INT8 szDBPwd[50] = {0};INT8 szSqlBuf[100] = {0};INT8 szRcvBuf[100] = {0};INT32 iRetVal = 0;void *pDBHandle = NULL;// 獲取數據庫各參數的值memcpy(szDBServerName, "db192_1_8_13",strlen("db192_1_8_13"));memcpy(szDBName, "dbp_166", strlen("dbp_166"));memcpy(szDBUser, "dbp_166", strlen("dbp_166"));memcpy(szDBPwd, "dbp_166", strlen("dbp_166"));// 連接數據庫pDBHandle = CDbCreateDb("Oracle", szDBServerName, szDBName,szDBUser, szDBPwd);if (pDBHandle == NULL) // 連接失敗{printf("ConnectDB failed! ServiceName:%s, DBName:%s, User:%s,Pwd:%s\n", szDBServerName, szDBName, szDBUser, szDBPwd);return -1;}printf("ConnectDB success! ServiceName:%s, DBName:%s, User:%s,Pwd:%s\n", szDBServerName, szDBName, szDBUser, szDBPwd);// 執行SQL語句并獲取結果// 獲取SQL語句memcpy(szSqlBuf, "select boxnumber from tb_test where id=1",strlen("select boxnumber from tb_test where id=1"));// 調用CDbExecSql函數執行SQL語句iRetVal = CDbExecSql(pDBHandle, szSqlBuf);if (iRetVal != 0) // 執行失敗{printf("CDbExecSql failed! RetVal=%d (ServiceName:%s, DBName:%s,User:%s, Pwd:%s)\n", iRetVal, szDBServerName, szDBName, szDBUser,szDBPwd);return -1;}// 調用CDbFetch函數獲取數據庫返回的結果iRetVal = CDbFetch(pDBHandle, szRcvBuf, 100);if (iRetVal != 0) // 執行失敗{printf("CDbFetch failed! RetVal=%d (ServiceName:%s, DBName:%s,User:%s, Pwd:%s)\n", iRetVal, szDBServerName, szDBName, szDBUser,szDBPwd);return -1;}// 打印從數據庫中獲取到的結果printf("RcvBuf=%s\n", szRcvBuf);return 0; }

說明:
1)CDbExecSql函數的兩個輸入參數分別是:數據庫句柄和SQL語句緩存,CDbFetch函數的三個輸入參數分別是:數據庫句柄、結果集緩存及緩存大小。其中,數據庫句柄是由CDbCreateDb函數執行之后獲得的。

2)CDbFetch函數必須要在CDbExecSql函數執行成功之后才能執行,因為前者要靠后者從數據庫中獲取結果。

總結

以上是生活随笔為你收集整理的Oracle调用接口(OCI)源码剖析(2):执行SQL语句并获取结果的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。