ODBC::SQLExecDirect返回-1 错误信息ORA-00604 ORA-01000

2023-05-16

  在通过使用微软提供的ODBC SDK读取数据库(SELECT)时,发现Oracle读着读着就读不到数据了(MySQL和SQL Server是正常的),经调试发现SQLExecDirect返回值为-1,在网上查找相关问题时看到一篇文章(ODBC中执行SQLExecDirect报错信息获取),于是就在程序出错的地方加了获取错误信息语句,代码strErrorMsg错误信息分别如下:

//.h
#pragma once
#include <sql.h>
#include <string>
#include <list>
#include <map>
using namespace std;

class CDataBaseClient
{
public:
	CDataBaseClient(void);
	~CDataBaseClient(void);

public:
	bool Connect(string strAddr, string strUser, string strPwd);
	void DisConnect();
	bool IsConnected();
	bool ExecuteSql(string strSql);
	bool QuerySql(string strSql, list<pair<string, string>> &lstCols);
	bool QuerySql(string strSql, list<string> &lstCol, list<string> &lstData);

private:
	SQLHENV m_hEnviroment;//环境句柄
	SQLHDBC m_hConnection;//连接句柄
};

//.cpp
bool CDataBaseClient::Connect(string strAddr, string strUser, string strPwd)
{
	SQLRETURN sqlReturn = SQLAllocEnv(&m_hEnviroment);
	if(sqlReturn != SQL_SUCCESS && sqlReturn != SQL_SUCCESS_WITH_INFO)
	{
		return false;
	}
	sqlReturn = SQLSetEnvAttr(m_hEnviroment, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0);

	sqlReturn = SQLAllocConnect(m_hEnviroment, &m_hConnection);
	if(sqlReturn != SQL_SUCCESS && sqlReturn != SQL_SUCCESS_WITH_INFO)
	{
		SQLFreeEnv(m_hEnviroment);
		m_hEnviroment = NULL;
		return false;
	}
	sqlReturn = SQLConnect(m_hConnection, (SQLCHAR*)strAddr.data(), SQL_NTS,(SQLCHAR*)strUser.data(), SQL_NTS,(SQLCHAR*)strPwd.data(), SQL_NTS);
	if(sqlReturn != SQL_SUCCESS && sqlReturn != SQL_SUCCESS_WITH_INFO)
	{
		SQLFreeConnect(m_hConnection);
		m_hConnection = NULL;
		SQLFreeEnv(m_hEnviroment);
		m_hEnviroment = NULL;
		return false;
	}
	return true;
}

void CDataBaseClient::DisConnect()
{
	if(m_hConnection)
	{
		SQLDisconnect(m_hConnection);
		SQLFreeConnect(m_hConnection);
		m_hConnection = NULL;
	}
	if(m_hEnviroment)
	{
		SQLFreeEnv(m_hEnviroment);
		m_hEnviroment = NULL;
	}
}

bool CDataBaseClient::IsConnected()
{
	if(m_hConnection)
	{
		return true;
	}
	return false;
}

//static int nNum = 0;
bool CDataBaseClient::QuerySql(string strSql, list<string> &lstCol, list<string> &lstData)
{
	//nNum += 1;
	SQLHSTMT hStmt; 
	SQLRETURN sqlReturn = SQLAllocStmt(m_hConnection, &hStmt);
	if(sqlReturn != SQL_SUCCESS && sqlReturn != SQL_SUCCESS_WITH_INFO)
	{
		return false;
	}
	sqlReturn = SQLExecDirect(hStmt,(SQLCHAR*)strSql.data(), strSql.length());
	if(sqlReturn != SQL_SUCCESS && sqlReturn != SQL_SUCCESS_WITH_INFO)
	{
// 		SQLLEN numRecs = 0;
// 		SQLGetDiagField(SQL_HANDLE_STMT, hStmt, 0, SQL_DIAG_NUMBER, &numRecs, 0, 0);
// 		SQLSMALLINT i = 1, MsgLen;
// 		SQLCHAR SqlState[6], Msg[SQL_MAX_MESSAGE_LENGTH];
// 		SQLINTEGER NativeError;
// 		while(i<=numRecs && (SQLGetDiagRec(SQL_HANDLE_STMT, hStmt, i, SqlState, &NativeError, Msg, sizeof(Msg), &MsgLen))!=SQL_NO_DATA)
// 		{
// 			string strErrorMsg = (char *)Msg;//报错时查看错误信息
// 			++i;
// 		}

		//报错时查看nNum的值为300
		SQLFreeStmt(hStmt, SQL_CLOSE);
		return false;
	}

	lstCol.clear();
	lstData.clear();
	if(SQLFetch(hStmt) != SQL_SUCCESS)
	{
		SQLFreeStmt(hStmt, SQL_CLOSE);
		return false;
	}
	SQLSMALLINT ColCount;
	SQLNumResultCols(hStmt, &ColCount);
	for(SQLSMALLINT i=1; i<=ColCount; i++)
	{
		char chColName[1024] = {0};
		SQLSMALLINT nLen = 1022;
		SQLColAttribute(hStmt, i, SQL_DESC_NAME, chColName, nLen, &nLen, NULL);
		lstCol.push_back(chColName);
	}
	do{
		for(SQLSMALLINT i=1; i<=ColCount; i++)
		{
			char chData[65536] = {0};
			SQLINTEGER nLen = 65534;
			SQLGetData(hStmt, i, SQL_C_CHAR, chData, nLen, &nLen);
			lstData.push_back(chData);
		}
		sqlReturn = SQLFetch(hStmt);
	}while(SQL_SUCCESS == sqlReturn);
	SQLFreeStmt(hStmt, SQL_CLOSE);
	return true;
}
[Oracle][ODBC][Ora]ORA-00604: error occurred at recursive SQL level 1
ORA-01000: maximum open cursors exceeded
ORA-00604: error occurred at recursive SQL level 1
ORA-01000: maximum open cursors exceeded
ORA-01000: maximum open cursors exceeded

  接下来又搜索“ORA-00604”和“ORA-01000”错误码信息,ORA-00604表明在数据库内部执行SQL语句时发生了(递归)错误,一般发生此错误时,还伴随着其它的错误,也就是当前的ORA-01000(即超过了最大打开游标数);ORA-01000有两种说法,分别是表空间不足打开的游标数量已达最大
  (1)先分析表空间:通过查看“表在哪个空间”及“表空间是否自增”发现,表是自增的,不存在表空间不足且dbf文件只有5M,分析过程如下。

查看表在哪个空间
查看表空间是否自增
  (2)再分析游标数量: 默认游标数为300,于是在程序中增加nNum变量调试,发现SQLExecDirect返回-1的时候nNum的值刚好是300

在这里插入图片描述
  通过以上分析得知问题根本所在:游标打开数超限(Oracle游标每次查询的时候都会打开,并且查询结束后游标并不会关闭,这样会导致打开的游标越来越多,最终超出上限。),继而猜测是否SQLFreeStmt(SQLHSTMT, SQL_CLOSE)释放语句句柄时未释放游标,于是又去搜“SQLHSTMT怎么释放干净”,找到一篇文章(SQLFreeStmt( m_hstmt, SQL_CLOSE)),看到文末了解到,SQLFreeStmt函数的功能由fOption参数的取值决定,注意到SQL_CLOSE与SQL_DROP的区别,于是把执行sql的函数中的SQL_CLOSE全部替换为SQL_DROP,运行一段时间,Oracle读取数据也正常了


分界线

  由于语句句柄是函数局部的,一直需要Alloc分配新的语句句柄(影响性能),又将SQLHSTMT作为类的成员,只在连接/断开数据源的时候分配/释放句柄,于是代码改动如下:

class CDataBaseClient
{
	//......
	
	SQLHSTMT m_hStmt;//语句句柄
};

bool CDataBaseClient::Connect(string strAddr,string strUser,string strPwd)
{
	//......

	sqlReturn = SQLAllocStmt(m_hConnection, &m_hStmt);
	if (sqlReturn != SQL_SUCCESS && sqlReturn != SQL_SUCCESS_WITH_INFO)
	{
		SQLFreeStmt(m_hStmt, SQL_DROP);
		m_hStmt = NULL;
		SQLFreeConnect(m_hConnection);
		m_hConnection = NULL;
		SQLFreeEnv(m_hEnviroment);
		m_hEnviroment = NULL;
		return false;
	}
	return true;
}

void CDataBaseClient::DisConnect()
{
	if(m_hStmt)//后分配先释放
	{
		SQLFreeStmt(m_hStmt, SQL_DROP);
		m_hStmt = NULL;
	}
	
	//......
}

bool CDataBaseClient::QuerySql(string strSql,list<string>&lstCol,list<string>&lstData)
{
	SQLRETURN sqlReturn=SQLExecDirect(m_hStmt,(SQLCHAR*)strSql.data(), strSql.length());
	if (sqlReturn != SQL_SUCCESS && sqlReturn != SQL_SUCCESS_WITH_INFO)
	{
		//......
		
		return false;
	}
	
	//......
	
	return true;
}

  运行程序后发现,Oracle和MySQL读取正常,SQL Server读取成功一次后续就读不到数据了,查看strErrorMsg错误信息为"[Microsoft][ODBC SQL Server Driver]无效的游标状态",然后试想在执行sql函数结束前关闭(SQL_CLOSE)与语句句柄相关联的游标,代码如下:

bool CDataBaseClient::QuerySql(string strSql, list<string>&lstCol, list<string>&lstData)
{
	SQLRETURN sqlReturn = SQLExecDirect(m_hStmt,(SQLCHAR*)strSql.data(), strSql.length());
	if(sqlReturn != SQL_SUCCESS && sqlReturn != SQL_SUCCESS_WITH_INFO)
	{
		//......
		
		SQLFreeStmt(m_hStmt, SQL_CLOSE);
		return false;
	}
	
	lstCol.clear();
	lstData.clear();
	if(SQLFetch(m_hStmt) != SQL_SUCCESS)
	{
		SQLFreeStmt(m_hStmt, SQL_CLOSE);
		return false;
	}
	
	//......
	
	SQLFreeStmt(m_hStmt, SQL_CLOSE);
	return true;
}

  加上SQLFreeStmt(m_hStmt, SQL_CLOSE)之后,运行程序,三种数据库读取数据均正常了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ODBC::SQLExecDirect返回-1 错误信息ORA-00604 ORA-01000 的相关文章

随机推荐

  • 【无标题】

    勘误 xff1a stm32F4xx参考手册中 34 11小节FIFO框架图中 最上面的DIEPTXF2 31 16 应为DIEPTXFn 31 16
  • HttpURLConnection高阶使用之kerberos认证解决方案

    1 HttpURLConnection 简介 sun net www protocol http HttpURLConnection是jdk中默认执行请求时使用 此HttpURLConnection 支持多种权限认证方案 xff0c Neg
  • 下篇 | 开发板AMR接收虚拟机Ubuntu传来的文件

    上篇笔记 xff1a 虚拟机Ubuntu向开发板AMR传送文件 已经做好了虚拟机向开发板传送文件的笔记啦 xff0c 然后有发送肯定有接收的 xff0c 不然就发空气啦 xff01 接下来 xff0c 写开发板如何接受虚拟机发送过来的文件的
  • 解决QT->setText()中文出现乱码问题,使用QString或者tr()均出现乱码。

    微软VC编译器源代码使用GB2312编码进行保存 源码中的汉字字符串在生成可执行文件的过程中被转换成了本地编码 Qt内部是使用Unicode编码 xff0c 即QString保存的是Unicode编码的字符串 Qt内部需要使用Unicode
  • Qt 下载图片并显示图片

    源码下载 xff1a 图片下载器 include 34 mainwindow h 34 include 34 ui mainwindow h 34 include lt QHostAddress gt include lt QDebug g
  • 海康威视 web3.0开发 常见错误 404,403

    海康威视 web3 0开发 常见错误 404 xff0c 403 配置情况 IE 浏览器 43 nginx 43 thinkPHP5 0 43 海康威视200万星光级红外球机1080P变焦云台球机DS 2DC4223IW D 关于如何使用网
  • 虚拟USB设备总结

    开发环境 xff1a windows 首先来总结最近研究的虚拟USB设备 xff0c 进而虚拟USB键盘成功了 xff0c 开心 xff01 得出了一个C S框架 xff0c 首先说一下客户端 客户端有两个部分 xff0c 用户空间工具和底
  • C#Winform:《DataGridViewComboBoxCell值无效》解决方案

    值无效 xff0c 可能是你下拉框选项 xff0c 没有这样的值 xff0c 而你却设置这个值 dataGridView1 Rows i Cells 1 Value 61 Hello World 解决方法就是在窗体的构造函数里添加如下代码
  • FFmpeg笔记

    1 下载 xff0c 配置 FFmpeg官网 xff1a https ffmpeg org 用的系统是Ubuntu18 04 所以直接apt get就可以了 sudo apt get install ffmpeg 2 简介 xff0c 上手
  • 《WPF中TextBox绑定Double类型数据,文本框不能输入小数点》解决方案

    在App cs文件里面 xff0c 重写OnStatup xff0c 添加下面一条语句即可 span class token keyword public span span class token keyword partial span
  • stm32 HAL库串口收发-中断接收DMA发送不定长数据

    使用的时候发现 xff1a 接收完一个字节立即用DMA的方式发送出去 xff0c 会出现数据的丢失 xff0c 如用串口调试助手发送1234 xff0c 返回的只有13 目前只能用缓存buf 43 协议结束 xff08 如0x0d 0x0a
  • headers Authorization

    var auth 61 96 host user host pass 96 const buf 61 Buffer from auth 39 ascii 39 strauth 61 buf toString 39 base64 39 con
  • 平衡车入门---MPU6050陀螺仪的使用

    平衡车入门 MPU6050陀螺仪的使用 一 MPU6050简介二 学习MPU6050的步骤三 I2C协议简介四 MPU6050硬件介绍五 MPU6050的几个重要寄存器六 原始数据的单位换算七 角度换算 滤波算法 一 MPU6050简介 M
  • C++ 为什么基类的析构函数要声明为虚函数

    1 为什么声明基类析构函数为虚函数 xff1f xff08 1 xff09 基类指针 指向 基类对象 xff1a 不用考虑基类析构函数是否声明为虚函数 xff08 2 xff09 基类指针 指向 派生类对象 xff1a 若基类析构函数不为虚
  • std::map find和count效率测试

    1 简介 在使用标准模板库中的map容器且遇到键值对的值为自定义struct或class类型时 xff0c 考虑到特殊场景 xff08 即不能确保key自始至终唯一 xff09 xff0c 若插入新元素 xff08 new 对象 xff09
  • 随机生成8位长字符串(大小写字母及数字组合)

    1 简要说明 项目上开发要用到随机生成一个8位长的字符串 xff08 类似Java工具类中的UUID xff09 xff0c 作为id来对同一事物的不同个体进行唯一标识 xff0c 如同一个班级里学生名字几乎不同 xff0c 偶尔会有重复
  • C++引用和指针区别

    1 C 43 43 引用和指针区别 xff1a 指针是一个新的变量 xff0c 指向另一个变量的地址 xff0c 我们可以通过访问这个地址来修改另一个变量 xff1b 而引用是一个别名 xff0c 对引用的操作就是对变量的本身进行操作指针可
  • TCP/UDP端口号

    大家好呀 xff0c 我是请假君 xff0c 今天又来和大家一起学习数通了 xff0c 今天要分享的知识是TCP UDP端口号 在IP网络中 xff0c 一个IP地址可以唯一地标识一个主机 但一个主机上却可能同时有多个程序访问网络 要标识这
  • C/C++ 电脑微信dat文件解密及工具分享

    1 前言 最近想整理下照片 xff08 回忆 怀旧 xff09 xff0c 以前也知道在微信pc端聊天时 xff0c 图片 视频 文档等文件会缓存在一个目录下 xff08 电脑微信 左下角三条杠 设置 文件管理 xff09 xff0c 点击
  • ODBC::SQLExecDirect返回-1 错误信息ORA-00604 ORA-01000

    在通过使用微软提供的ODBC SDK读取数据库 xff08 SELECT xff09 时 xff0c 发现Oracle读着读着就读不到数据了 xff08 MySQL和SQL Server是正常的 xff09 xff0c 经调试发现SQLEx