OCIStmtExecute发送接收处理的定位

前言

写了一个OCI接口测试程序,执行一个SQL, 看看发送接收处理都在哪个地址上实现的。

前置条件准备

在虚拟机中搭建oracle服务器,调通环境。
用sqldeveloper.exe能连接数据库。
在开发机上安装oracle开发组件,tnsping orcl通过。
写好OCI测试程序,可以正常执行SQL,并调用OCI接口分析出返回的查询语句结果集。
用wireshark对虚拟网卡vm8抓包,可以看到执行OCIStmtExecute后,抓到发出一个包(select * …)和回包2个。

实验

IDA加载OCI测试程序,断在OCIStmtExecute的调用处。F9跑起,命中后,单步,一直追到看到发送数据和接收数据为止。
在调试代码中,经过了8,9个OCI内部函数后,达到了发送接收数据的反汇编代码。

为了方便调试,本来在找到最后要调试的点后,应该写个IDA脚本来一键执行到要调试处。可惜最近一直都没玩IDA脚本,只好写了一个C程序辅助,手工来一步一步的下断点。
等这个任务完成后,再复习一下IDA脚本的编写。

IDA调试地址提示器程序

// debug_addr_calc.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <Windows.h>
#include <stdlib.h>
#include <stdio.h>

#define LINE_80 "--------------------------------------------------------------------------------"

unsigned long long hex_addr_buf_to_ull(const char* sz_hex);
int char_to_int(char c_in);
void ull_to_hex_addr_buf(/*OUT*/ char* sz_hex, int ilen_buf, unsigned long long ull_in);

void input_addr(const char* psz_tip, /*OUT*/ unsigned long long& ull_addr);
void show_addr(const char* psz_tip, /*OUT*/ unsigned long long& ull_addr, unsigned long long ull_addr_offset);

// 调试之前,将IDA断点都拿掉,
//	*防止oracle DLL 未加载, 引起IDA断点下在无效区域报错.
//	*dll加载时,地址随机化,以前下的断点已经无效了,在第二次运行时,必须将以前的无效断点都拿掉。
// IDA7.0 => Debugger => Breakpoints => Breakpoint list => 选择第一个断点, 按住del键不放,将断点全部删掉。
// 用IDA载入OCI测试程序,将第一个断点下在测试代码中的OCIStmtExecute
// 用IDA带着测试程序跑起来,断下后,启动本程序,按照提示,依次下断点,最后到达底层的发送接收实现

// 以下是oracle 11g_r2 的SQL发送接收函数的代码实现到达路径
int _tmain(int argc, _TCHAR* argv[])
{
	unsigned long long ull_addr = 0;

	printf("OCI debug addr calc\r\n");

//	发送并接收了数据的实现
//oci.dll:0000000180004388 oci_OCIStmtExecute: ; entry
	input_addr("oci_OCIStmtExecute", ull_addr);

//oci.dll:000000018000443D call    rax ; qword_18009E938 ; offset = 0xb5;
	show_addr("call    rax", ull_addr, 0xb5);

//oraclient11.dll:0000000003CE4B00 oraclient11_OCIStmtExecute: ; entry
//oraclient11.dll:0000000003CE4B00 xchg    ax, ax ;
	input_addr("oraclient11_OCIStmtExecute", ull_addr);

//oraclient11.dll:0000000003CE4B41 call    near ptr oraclient11_kpuexec ; offset = 0x41
	show_addr("call    near ptr oraclient11_kpuexec", ull_addr, 0x41);

//oraclient11.dll:0000000003E2AD30 oraclient11_kpuexec:
//oraclient11.dll:0000000003E2AD30 xchg    ax, ax ;
	input_addr("oraclient11_kpuexec", ull_addr);

//oraclient11.dll:0000000003E2B87E call    near ptr oraclient11_kpurcsc ; offset = 0xB4E
//oraclient11.dll:0000000003E2D351 call    near ptr oraclient11_kpurcsc ; offset = 0x2621
	show_addr("call    near ptr oraclient11_kpurcsc", ull_addr, 0x2621);

//oraclient11.dll:0000000003E2D5FC call    near ptr oraclient11_kpurcsc ; offset = 0x28cc
//oraclient11.dll:0000000003E2D6E8 call    near ptr oraclient11_kpurcsc ; offset = 0x29b8
//
//oraclient11.dll:0000000003EAB292 oraclient11_kpurcsc:
//oraclient11.dll:0000000003EAB292 xchg    ax, ax ;
	input_addr("oraclient11_kpurcsc", ull_addr);

//oraclient11.dll:0000000003EAB323 call    near ptr oraclient11_upirtrc ; offset = 0x91
	show_addr("call    near ptr oraclient11_upirtrc", ull_addr, 0x91);

	// oraclient11.dll:000000000368AE96 oraclient11_upirtrc proc near
	input_addr("oraclient11_upirtrc", ull_addr);

	// oraclient11.dll:0000000003C9AF0D call    near ptr unk_3CB4B9E
	show_addr("oraclient11.dll:0000000003C9AF0D call    near ptr unk_3CB4B9E", ull_addr, 0x0000000003B0AF0D - 0x0000000003B0AE96);

	// oraclient11.dll:0000000003B24B9E loc_3B24B9E: // 这函数里面很像是在组包
	input_addr("oraclient11.dll:0000000003B24B9E loc_3B24B9E:", ull_addr);

	// oraclient11.dll:0000000003B25213 call    qword ptr [rax+20h]
	show_addr("oraclient11.dll:0000000003B25213 call    qword ptr [rax+20h]", ull_addr, 0x0000000003B25213 - 0x0000000003B24B9E);

	// oran11.dll:0000000003D185C0 oran11_nioqwa:
	input_addr("oran11.dll:0000000003D185C0 oran11_nioqwa:", ull_addr);

	// oran11.dll:0000000003D185F5 call    r14
	show_addr("oran11.dll:0000000003D185F5 call    r14", ull_addr, 0x0000000003D185F5 - 0x0000000003D185C0);

	printf("%s\r\n", LINE_80);
	printf("break here, when go here second time, will be send packet and received\r\n");
	printf("%s\r\n", LINE_80);

	// oracommon11.dll:000000000442D496 oracommon11_ttcdrv:
	printf("when execute 'call    r14' second, input below addr\r\n");
	input_addr("oracommon11.dll:000000000442D496 oracommon11_ttcdrv:", ull_addr);

	// oracommon11.dll:000000000442DA6B call    qword ptr [rsi+10h]
	show_addr("oracommon11.dll:000000000442DA6B call    qword ptr [rsi+10h]", ull_addr, 0x000000000442DA6B - 0x000000000442D496);

	// oran11.dll:000000000490438A oran11_nioqrc:
	input_addr("oran11.dll:00000000034C438A oran11_nioqrc:", ull_addr);

	// oran11.dll:00000000049044C6 call    near ptr oran11_nsbsend
	show_addr("oran11.dll:00000000049044C6 call    near ptr oran11_nsbsend", ull_addr, 0x00000000049044C6 - 0x000000000490438A);

	// oran11.dll:0000000004904595 call    near ptr oran11_nsbrecv
	show_addr("oran11.dll:0000000004904595 call    near ptr oran11_nsbrecv", ull_addr, 0x0000000004904595 - 0x000000000490438A);

	// rcx 是发送的数据流(是tns包中的纯data数据 : 11 6b 0406000000a001000001000000035e056180000000000000...)
	/*
	Data
	Data Flag: 0x0000
	Data ID: Piggy back function follow (0x11)
	Call ID: Session switching piggyback (V8) (0x6b)
	Data (314 bytes)
	Data: 0406000000a001000001000000035e056180000000000000...
	[Length: 314]
	*/
	// base : oran11.dll:00000000054A438A oran11_nioqrc:
	// oran11.dll:00000000054A4506 mov     [rbx+20h], rcx
	show_addr("oran11_nsbsend pure data : oran11.dll:00000000054A4506 mov     [rbx+20h], rcx", ull_addr, 0x00000000054A4506 - 0x00000000054A438A);
	printf("view rcx on memory window\r\n");

	/*
	oran11.dll:00000000048244C6 call    near ptr oran11_nsbsend
	edx 是tns包长度326
	Transparent Network Substrate Protocol
	Packet Length: 326
	Packet Checksum: 0x0000
	Packet Type: Data (6)
	Reserved Byte: 00
	Header Checksum: 0x0000
	Data
	Data Flag: 0x0000
	Data ID: Piggy back function follow (0x11)
	Call ID: Session switching piggyback (V8) (0x6b)
	Data (314 bytes)

	oran11.dll:00000000048244CB mov     edx, 1

	oran11.dll:00000000048244FE mov     rcx, [r12+328h]
	r12是发送数据的上下文指针, [r12+328h] 是 tns数据(DataID + CallID + Data(314bytes))

	oran11.dll:0000000004824595 call    near ptr oran11_nsbrecv
	oran11.dll:000000000482459F mov     rax, [r12+3D0h]
	r12是发送数据的上下文指针
	[r12+3D0h] 是指针,指向DataID 0x10, 后面就是tns纯数据

	// 在上下文中保存发送数据的tns数据指针
	oran11.dll:0000000004824506 mov     [rbx+20h], rcx
	oran11.dll:000000000482450A mov     [rbx+10h], rcx

	// 在上下文中保存接收的tns数据指针
	oran11.dll:00000000048245B9 mov     [rbx+18h], rax
	oran11.dll:00000000048245BD mov     [rbx+28h], rax

	// 接收的tns数据长度(DataID + Data) = 908
	oran11.dll:00000000048245E8 mov     rcx, [r12+3E0h]

	// 处理接收的数据(取DataID)
	// get_tns_data_id_4B6060C
	oran11.dll:000000000482461F call    near ptr unk_4B6060C

	// 保存DataID 0x10
	oran11.dll:0000000004B60939 mov     r9b, [rdx]

	// 取接收的tns数据
	oran11.dll:0000000004824624 mov     rdx, [rbx+18h]

	// 取接收的tns纯数据
	oran11.dll:000000000482462B add     rdx, r13 // r13 = 1
	oran11.dll:000000000482462E mov     [rbx+18h], rdx

	oraclient11.dll:000000000310844B call    near ptr oraclient11_kpuhhrsm

	*/

	system("pause");
	return 0;
}

void input_addr(const char* psz_tip, /*OUT*/ unsigned long long& ull_addr)
{
	char sz_input[MAXBYTE + 1] = {'\0'};

	printf("input addr => %s:", (NULL != psz_tip) ? psz_tip : "NULL");
	memset(sz_input, 0, sizeof(sz_input));
	scanf("%255s", sz_input);
	ull_addr = hex_addr_buf_to_ull(sz_input);

	ull_to_hex_addr_buf(sz_input, (int)sizeof(sz_input), ull_addr);
	printf("addr %s = %s\r\n", (NULL != psz_tip) ? psz_tip : "NULL", sz_input);
}

void show_addr(const char* psz_tip, /*OUT*/ unsigned long long& ull_addr, unsigned long long ull_addr_offset)
{
	unsigned long long ull_addr_next = 0;
	char sz_input[MAXBYTE + 1] = {'\0'};

	ull_addr_next = ull_addr + ull_addr_offset;
	ull_to_hex_addr_buf(sz_input, (int)sizeof(sz_input), ull_addr_next);
	printf("addr %s = %s\r\n", (NULL != psz_tip) ? psz_tip : "NULL", sz_input);
}

unsigned long long hex_addr_buf_to_ull(const char* sz_hex)
{
	unsigned long long ull_rc = 0;
	const char* psz_now = sz_hex;
	char c_tmp = '\0';
	
	while ((NULL != psz_now) && ('\0' != *psz_now)) {
		ull_rc *= 16;
		c_tmp = *psz_now;
		psz_now++;
		ull_rc += (int)char_to_int(c_tmp);
	}

	return ull_rc;
}

int char_to_int(char c_in)
{
	int i_rc = (int)c_in;

	if ((c_in >= '0') && (c_in <= '9')) {
		i_rc -= (int)'0';
	} else if ((c_in >= 'a') && (c_in <= 'f')) {
		i_rc -= (int)'a';
		i_rc += 10;
	} else if ((c_in >= 'A') && (c_in <= 'F')) {
		i_rc -= (int)'A';
		i_rc += 10;
	}

	return i_rc;
}

void ull_to_hex_addr_buf(/*OUT*/ char* sz_hex, int ilen_buf, unsigned long long ull_in)
{
	if (NULL != sz_hex) {
		memset(sz_hex, 0, ilen_buf);
		sprintf(sz_hex, "%I64x", ull_in);
	}
}

OCI测试程序

// @file oci_test_on_vs2017.cpp
// @brief test oci interface

#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <string>

// OCI开发环境配置
// 远端oracle服务器端装好,配好TNS服务名称
//
// 安装oracle客户端软件时,选第3项(开发工具). 
// oracle客户端安装完后,用自带的网络助手配置监听器和远端的TNS服务名称
//
// 将工程设定为win64, 包含进OCI头文件和库文件.
// 在打开远端oracle服务器(进入服务器桌面)的情况下,就可以运行调试测试程序了.
// 不用配ODBS的DSN.

#include "oci.h"
// oci.lib is win64, win32编译不过.
#pragma comment(lib, "oci.lib")

// 用oracle网络助手配置的远端网络服务名称, 不是ODBC助手配置出来的dsn名称
#define REMOTE_TNS_SERVICE_NAME "orcl" // 服务名称不区分大小写
#define DB_USER_NAME "system"
#define DB_USER_PWD "system"

typedef struct _tag_col_info{
	char* m_psz_name;
	int m_i_len_name;

	int m_i_data_type_org;
	int m_i_data_type_now;
	char* m_psz_data;
	int m_i_len_data;

	_tag_col_info() {
		m_psz_name = NULL;
		m_i_len_name = 0;

		m_i_data_type_org = SQLT_CHR;
		m_i_data_type_now = SQLT_CHR;
		m_psz_data = NULL;
		m_i_len_data = 0;
	}

	void clear() {
		if (NULL != m_psz_name) {
			delete [] m_psz_name;
			m_psz_name = NULL;
		}

		if (NULL != m_psz_data) {
			delete [] m_psz_data;
			m_psz_data = NULL;
		}

		m_i_len_name = 0;
		m_i_len_data = 0;
		m_i_data_type_org = SQLT_CHR;
		m_i_data_type_now = SQLT_CHR;
	}
}TAG_COL_INFO;

std::string get_oci_error(const char* psz_tip, OCIError* h_oci_error);
void print_oci_error(const char* psz_tip, OCIError* h_oci_error);
void do_oci_task(OCIEnv* h_oci_env, OCIServer* h_oci_server, OCIError* h_oci_error, OCISvcCtx* h_oci_context, OCISession* h_oci_user);

void case_oci_opt();

int g_i_columns_cnt = 0;
TAG_COL_INFO g_col_info[100];

int _tmain(int argc, _TCHAR* argv[])
{
	case_oci_opt();

	printf("END\n");
	system("pause");
	return 0;
}

void case_oci_opt()
{
	sword sw_rc = 0;
	sword sw_tmp = 0;
	OCIEnv* h_oci_env = NULL; // 环境句柄
	OCIServer* h_oci_server = NULL; // 服务器句柄
	OCIError* h_oci_error = NULL; // 错误句柄
	OCISvcCtx* h_oci_context = NULL; // 上下文句柄
	OCISession* h_oci_user = NULL; // 用户句柄

	sb4 errcode = 0;
	char sz_buf[4096] = {'\0'};

	do {
		// 打印数据库连接信息
		printf("connect local tns service name [%s], user name = [%s], password = [%s]\r\n",
			REMOTE_TNS_SERVICE_NAME,
			DB_USER_NAME,
			DB_USER_PWD);
			
		// 创建环境句柄(线程和环境对象)
		sw_rc = OCIEnvCreate(&h_oci_env, OCI_THREADED | OCI_OBJECT, (dvoid*)0, 0, 0, 0, (size_t)0, (dvoid**)0);
		if (OCI_SUCCESS != sw_rc) {
			print_oci_error("error : create env handle", h_oci_error);
			break;
		}

		// 创建服务器句柄
		sw_rc = OCIHandleAlloc((dvoid*)h_oci_env, (dvoid**)&h_oci_server, OCI_HTYPE_SERVER, 0, (dvoid**)0);
		if (OCI_SUCCESS != sw_rc) {
			print_oci_error("error : create service handle", h_oci_error);
			break;
		}

		// 创建错误句柄
		sw_rc = OCIHandleAlloc((dvoid*)h_oci_env, (dvoid**)&h_oci_error, OCI_HTYPE_ERROR, 0, (dvoid**)0);
		if (OCI_SUCCESS != sw_rc) {
			print_oci_error("error : create error handle", h_oci_error);
			break;
		}

		// OCI连接的不是ODBC DSN名称
		// my_oracle_dsn
		// ORA-12154: TNS: 无法解析指定的连接标识符

		// OCI连接的是远端TNS服务名称
		// TNSPING ORCL
		// 成功

		// 如果远端的oracle服务器关了,这里会显示错误:连接超时
		// ORA-12170: TNS: 连接超时

		// 连接远程数据库(tns服务名称)
		sw_rc = OCIServerAttach(h_oci_server, h_oci_error,
			(text*)REMOTE_TNS_SERVICE_NAME,
			(sb4)strlen(REMOTE_TNS_SERVICE_NAME),
			OCI_DEFAULT);
		// packet 1~18

		if (OCI_SUCCESS != sw_rc) {
			print_oci_error("error : remote database connect", h_oci_error);
			break;
		}

		// 创建上下文
		sw_rc = OCIHandleAlloc((dvoid*)h_oci_env, (dvoid**)&h_oci_context, OCI_HTYPE_SVCCTX, 0, (dvoid**)0);
		// packet 19~20
		if (OCI_SUCCESS != sw_rc) {
			print_oci_error("error : create context", h_oci_error);
			break;
		}

		// 设置上下文属性
		sw_rc = OCIAttrSet((dvoid**)h_oci_context, OCI_HTYPE_SVCCTX, (dvoid*)h_oci_server, (ub4)0, OCI_ATTR_SERVER, h_oci_error);
		if (OCI_SUCCESS != sw_rc) {
			print_oci_error("error : set context", h_oci_error);
			break;
		}

		// 创建用户句柄
		sw_rc = OCIHandleAlloc((dvoid*)h_oci_env, (dvoid**)&h_oci_user, OCI_HTYPE_SESSION, 0, (dvoid**)0);
		if (OCI_SUCCESS != sw_rc) {
			print_oci_error("error : create user", h_oci_error);
			break;
		}

		// 设置用户名
		sw_rc = OCIAttrSet((dvoid*)h_oci_user, OCI_HTYPE_SESSION, (dvoid*)DB_USER_NAME, (ub4)strlen(DB_USER_NAME), OCI_ATTR_USERNAME, h_oci_error);
		if (OCI_SUCCESS != sw_rc) {
			print_oci_error("error : set user name", h_oci_error);
			break;
		}

		// 设置口令
		sw_rc = OCIAttrSet((dvoid*)h_oci_user, OCI_HTYPE_SESSION, (dvoid*)DB_USER_PWD, (ub4)strlen(DB_USER_PWD), OCI_ATTR_PASSWORD, h_oci_error);
		if (OCI_SUCCESS != sw_rc) {
			print_oci_error("error : set user password", h_oci_error);
			break;
		}

		// 会话开始
		sw_rc = OCISessionBegin(h_oci_context, h_oci_error, h_oci_user, OCI_CRED_RDBMS, OCI_DEFAULT);
		// packet 21~26
		if (OCI_SUCCESS != sw_rc) {
			print_oci_error("error : session begin", h_oci_error);
			break;
		}

		// 在会话上设置用户信息
		sw_rc = OCIAttrSet((dvoid*)h_oci_context, OCI_HTYPE_SVCCTX, (dvoid*)h_oci_user, (ub4)0, OCI_ATTR_SESSION, h_oci_error);
		if (OCI_SUCCESS != sw_rc) {
			print_oci_error("error : set user info on service handle", h_oci_error);
			break;
		}

		// 干活
		do_oci_task(h_oci_env, h_oci_server, h_oci_error, h_oci_context, h_oci_user);

		printf("ok : db operation over\r\n");
	} while (0);

	// 会话结束
	sw_rc = OCISessionEnd(h_oci_context, h_oci_error, h_oci_user, OCI_DEFAULT);
	// packet 39~41
	if (OCI_SUCCESS != sw_rc) {
		print_oci_error("error : end session", h_oci_error);
	}

	// 断开连接
	sw_rc = OCIServerDetach(h_oci_server, h_oci_error, OCI_DEFAULT);
	// packet 42`46
	if (OCI_SUCCESS != sw_rc) {
		print_oci_error("error : detach server", h_oci_error);
	}

	// --------------------------------------------------------------------------------
	// 释放句柄
	// --------------------------------------------------------------------------------
	sw_rc = OCIHandleFree((void*)h_oci_user, OCI_HTYPE_SESSION);
	if (OCI_SUCCESS != sw_rc) {
		print_oci_error("error : OCI_HTYPE_SESSION", h_oci_error);
	}

	sw_rc = OCIHandleFree((void*)h_oci_context, OCI_HTYPE_SVCCTX);
	if (OCI_SUCCESS != sw_rc) {
		print_oci_error("error : OCI_HTYPE_SVCCTX", h_oci_error);
	}

	sw_rc = OCIHandleFree((void*)h_oci_error, OCI_HTYPE_ERROR);
	if (OCI_SUCCESS != sw_rc) {
		print_oci_error("error : OCI_HTYPE_ERROR", NULL);
	}

	sw_rc = OCIHandleFree((void*)h_oci_server, OCI_HTYPE_SERVER);
	if (OCI_SUCCESS != sw_rc) {
		print_oci_error("error : OCI_HTYPE_SERVER", NULL);
	}

	sw_rc = OCIHandleFree((void*)h_oci_env, OCI_HTYPE_ENV);
	if (OCI_SUCCESS != sw_rc) {
		print_oci_error("error : OCI_HTYPE_ENV", NULL);
	}
}

std::string get_oci_error(const char* psz_tip, OCIError* h_oci_error)
{
	char sz_buf[4096] = { '\0' };
	sword sw_rc = 0;
	sb4 errcode = 0;
	std::string str_rc = "";

	if (NULL != psz_tip) {
		str_rc += psz_tip;
	}

	str_rc += "\r\n";

	if (NULL != h_oci_error) {
		sw_rc = OCIErrorGet(
			h_oci_error,
			(ub4)1,
			(text*)NULL,
			&errcode,
			(OraText*)sz_buf,
			(ub4)sizeof(sz_buf),
			(b4)OCI_HTYPE_ERROR);

		if (OCI_SUCCESS == sw_rc) {
			str_rc += "\t";
			str_rc += sz_buf;
		}
	}

	return str_rc;
}

void print_oci_error(const char* psz_tip, OCIError* h_oci_error)
{
	printf("%s\r\n", get_oci_error(psz_tip, h_oci_error).c_str());
}

void do_oci_task(OCIEnv* h_oci_env, OCIServer* h_oci_server, OCIError* h_oci_error, OCISvcCtx* h_oci_context, OCISession* h_oci_user)
{
	// 从oracle原生数据库中选择一条唯一的记录
	// select * from help where topic = 'ACCEPT' AND SEQ = 7;
	
	// OraText* ora_text_select = (OraText*)"select * from help where topic = 'ACCEPT' AND SEQ = 7"; // 只有1条
	OraText* ora_text_select = (OraText*)"select * from help where topic = 'ACCEPT' AND SEQ < 7"; // 共7条

	sword sw_rc = 0;
	OCIStmt* h_oci_stmt = NULL; // SQL语句句柄
	OCIDefine* h_oci_define = NULL;
	OCIParam* h_oci_param = NULL;
	OraText* colName = NULL;
	ub4 colNameSize = 0;
	
	ub2 stmt_type = 0; // SQL语句类型
	ub4 fieldCount = 0; // 结果集字段数量
	ub4 i_index = 0;
	int i_row_index = 0;

	ub4 col_len = 0;
	ub4 col_lenSize = 0;
	int dtypeNew = 0;

	ub4 dtype = 0;

	do {
		if ((NULL == h_oci_env)
			|| (NULL == h_oci_server)
			|| (NULL == h_oci_error)
			|| (NULL == h_oci_user)
			|| (NULL == h_oci_context)) {
			printf("oci handle invalid\r\n");
			break;
		}

		printf("do oci task\r\n");

		// 建立SQL语句句柄
		sw_rc = OCIHandleAlloc(h_oci_env, (void**)&h_oci_stmt, OCI_HTYPE_STMT, (size_t)0, (dvoid**)0);
		if (OCI_SUCCESS != sw_rc) {
			print_oci_error("error : create OCI_HTYPE_STMT", h_oci_error);
			break;
		}

		// 准备SQL语句
		sw_rc = OCIStmtPrepare(h_oci_stmt, h_oci_error, ora_text_select, (ub4)strlen((const char*)ora_text_select), (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT);
		if (OCI_SUCCESS != sw_rc) {
			print_oci_error("error : OCIStmtPrepare", h_oci_error);
			break;
		}

		// 执行SQL
		printf("sw_rc = OCIStmtExecute(h_oci_context, h_oci_stmt, h_oci_error, (ub4)0, (ub4)0, (OCISnapshot*)0, (OCISnapshot*)0, OCI_DEFAULT);\r\n");
		sw_rc = OCIStmtExecute(h_oci_context, h_oci_stmt, h_oci_error, (ub4)0, (ub4)0, (OCISnapshot*)0, (OCISnapshot*)0, OCI_DEFAULT);
		// packet 27~29
		if (OCI_SUCCESS != sw_rc) {
			print_oci_error("error : OCIStmtExecute", h_oci_error);
			break;
		}

		// 获取SQL语句类型
		sw_rc = OCIAttrGet(h_oci_stmt, OCI_HTYPE_STMT, &stmt_type, NULL, OCI_ATTR_STMT_TYPE, h_oci_error);
		if (OCI_SUCCESS != sw_rc) {
			print_oci_error("error : OCI_ATTR_STMT_TYPE", h_oci_error);
			break;
		}

		// 取结果集列信息
		if (OCI_STMT_SELECT == stmt_type) {
			printf("query result set :\r\n");

			printf("sw_rc = OCIAttrGet(h_oci_stmt, OCI_HTYPE_STMT, &fieldCount, NULL, OCI_ATTR_PARAM_COUNT, h_oci_error);\r\n");
			sw_rc = OCIAttrGet(h_oci_stmt, OCI_HTYPE_STMT, &fieldCount, NULL, OCI_ATTR_PARAM_COUNT, h_oci_error);
			if (OCI_SUCCESS != sw_rc) {
				print_oci_error("error : OCI_ATTR_STMT_TYPE", h_oci_error);
				break;
			}

			printf("query result set columns = %d\r\n", fieldCount);
			g_i_columns_cnt = fieldCount;

			for (i_index = 0; i_index < fieldCount; i_index++) {
				h_oci_param = NULL;
				dtype = 0;

				printf("columns %d : \r\n", i_index + 1);
				ub4 dtypeSize = sizeof(dtype);
				sw_rc = OCIParamGet(h_oci_stmt, OCI_HTYPE_STMT, h_oci_error, (void**)&h_oci_param, i_index + 1);
				if (OCI_SUCCESS != sw_rc)
				{
					print_oci_error("error : OCIParamGet", h_oci_error);
					break;
				}

				sw_rc = OCIAttrGet(h_oci_param, OCI_DTYPE_PARAM, &dtype, &dtypeSize, OCI_ATTR_DATA_TYPE, h_oci_error);
				if (OCI_SUCCESS != sw_rc)
				{
					print_oci_error("error : OCIAttrGet", h_oci_error);
					break;
				}

				g_col_info[i_index].m_i_data_type_org = (int)dtype;
				printf("\tg_col_info[%d].m_i_data_type_org = %d\r\n", i_index, g_col_info[i_index].m_i_data_type_org);

				colName = NULL;
				colNameSize = sizeof(colName);
				sw_rc = OCIAttrGet(h_oci_param, OCI_DTYPE_PARAM, &colName, &colNameSize, OCI_ATTR_NAME, h_oci_error);
				if (OCI_SUCCESS != sw_rc)
				{
					print_oci_error("error : OCIAttrGet", h_oci_error);
					break;
				}

				g_col_info[i_index].m_i_len_name = (int)colNameSize;
				g_col_info[i_index].m_psz_name = new char[g_col_info[i_index].m_i_len_name + 1];
				memset(g_col_info[i_index].m_psz_name, 0, g_col_info[i_index].m_i_len_name + 1);
				strcpy_s(g_col_info[i_index].m_psz_name, g_col_info[i_index].m_i_len_name + 1, (char*)colName);

				printf("\tname = %s\r\n", (char*)colName);
				printf("\tname len = %d\r\n", (int)colNameSize);

				col_len = 0;
				col_lenSize = sizeof(col_len);
				dtypeNew = SQLT_CHR;
				switch (dtype)
				{
				case SQLT_DAT:
				case SQLT_DATE:
				case SQLT_TIME:
				case SQLT_TIME_TZ:
				case SQLT_TIMESTAMP:
				case SQLT_TIMESTAMP_TZ:
				case SQLT_TIMESTAMP_LTZ:
				{
					dtypeNew = SQLT_ODT;
					col_len = sizeof(OCIDate);
				}
				break;
				case SQLT_CLOB:
				case SQLT_CHR:
				case SQLT_INT:
				case SQLT_UIN:
				case SQLT_NUM:
				case SQLT_FLT:
				case SQLT_STR:
				case SQLT_VNU:
				case SQLT_LNG:
				case SQLT_VCS:
				case SQLT_LVC:
				case SQLT_AFC:
				case SQLT_AVC:
				{
					sw_rc = OCIAttrGet(h_oci_param, OCI_DTYPE_PARAM, &col_len, &col_lenSize, OCI_ATTR_DATA_SIZE, h_oci_error);
					if (OCI_SUCCESS != sw_rc)
					{
						print_oci_error("error : OCIAttrGet", h_oci_error);
						break;
					}

					printf("\tdata len = %d\r\n", (int)col_len);
					dtypeNew = SQLT_CHR;
				}
				break;
				default:
					// assert(0);
					break;
				}

				g_col_info[i_index].m_i_data_type_now = (int)dtypeNew;
				printf("\tg_col_info[%d].m_i_data_type_now = %d\r\n", i_index, g_col_info[i_index].m_i_data_type_now);

				g_col_info[i_index].m_i_len_data = (int)col_len;
				g_col_info[i_index].m_psz_data = new char[g_col_info[i_index].m_i_len_data + 1];
				memset(g_col_info[i_index].m_psz_data, 0, g_col_info[i_index].m_i_len_data + 1);

				h_oci_define = NULL;
				sw_rc = OCIDefineByPos(h_oci_stmt, &h_oci_define, h_oci_error, i_index + 1, g_col_info[i_index].m_psz_data, col_len * sizeof(char), dtypeNew, 0, 0, 0, OCI_DEFAULT);
				if (OCI_SUCCESS != sw_rc)
				{
					print_oci_error("error : OCIDefineByPos", h_oci_error);
					break;
				}

				printf("----------------------------------------\r\n");
			}
		}

		//// 遍历行集
		//i_row_index = 0;
		//do {
		//	sw_rc = OCIStmtFetch(h_oci_stmt, h_oci_error, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
		//	// 如果是查第一行,并不发收包,可能执行后,返回的数据中已经包含第一行
		//	// packet 30~32 如果数据不够了,会继续请求包。
		//	// packet 33~35
		//	// packet 36~38
		//	if (OCI_NO_DATA == sw_rc)
		//	{
		//		break;
		//	}

		//	for (i_index = 0; i_index != g_i_columns_cnt; i_index++)
		//	{
		//		printf("row[%d]col[%d] = %s\r\n", i_row_index, i_index, (NULL != g_col_info[i_index].m_psz_data) ? g_col_info[i_index].m_psz_data : "NULL");
		//	}
		//	printf("----------------------------------------\r\n");
		//	i_row_index++;
		//} while (1);

		// 释放资源
		for (i_index = 0; i_index != g_i_columns_cnt; i_index++)
		{
			g_col_info[i_index].clear();
		}
	} while (0);

	// 释放oci句柄
	sw_rc = OCIHandleFree((void*)h_oci_stmt, OCI_HTYPE_STMT);
	if (OCI_SUCCESS != sw_rc) {
		print_oci_error("error : OCI_HTYPE_STMT", NULL);
	}
}

猜你喜欢

转载自blog.csdn.net/LostSpeed/article/details/78994782