编程思想是这样的:
1,用 socket 建立守候进程,等待客户端发来SQL语句,并且返回数据库数值
2,用PROC建立了一个类,并且用PROC预编译通过,现在出现一下问题因为 socket 使用的是 fork() 多进程编程,每次接收客户端发送来的SQL语句后,就建立一个新进程,但是每个进程执行完毕后游标不自动清空,所以接收没有几个就被占满了,出现一下语句:
ORA-01000: maximum open cursors exceeded但是,我的类里面明明给游标关闭了呀?一下就是类的全部内容,请各位大侠帮忙看看。
因为太长,我分段,都是连续的:/*-------------------------------------------------------------------------
类名称:QDBC
类功能:连接ORACLE数据库专用类
设计日:2004-7-16
设计者:邱洋(Q龙-QDragon)
邮箱:[email protected]
修改日期:2004-7-19
修改内容:绝对不能在头文件中加入 sqlcpr.h 这个函数声明文件 修改日期:2004-7-20
修改内容:有时候要也要将自己的头文件放在系统头文件的前面 修改日期:2004-7-30
修改内容:将 ReturnRes() 函数中 Mode==1 部分返回了 0,并且将 RES.Fields 和 RES.Count 赋值为 0
--------------------------------------------------------------------------*/
#include "../b_qdbc.hpp"
#include <setjmp.h>
#include <sqlcpr.h>
#include <sqlda.h>
#include <sqlca.h>
/////////////////////////////////////////////////////////////////////
#define MAX_ITEMS 100 //定义选择列表项和绑定变量的最大个数
#define MAX_VNAME_LEN 30 //定义选择列表项、绑定变量名称的最大长度
#define MAX_INAME_LEN 30 //定义指示变量名称的最大长度
/////////////////////////////////////////////////////////////////////class QDBC :public B_QDBC
{
public:
//构造函x数
QDBC(char* cHostName, char* cUserName, char* cPassword, char* cDBoSerName, char cDBMode);
~QDBC();
//操作函数
bool Connect(); //建立连接
bool Disconnect(); //断开连接
bool GetRES(); //取得资源(如果是MYSQL也一次取完--根据返回记录类)
int ReturnRes(char *SqlQuary, int Mode);//获取资源(Mode=0 是资料语句 Mode=1 是操作语句) private:
void sql_error();
void alloc_descriptors(int, int, int);
void set_bind_variables();
int process_select_list();
void free_res();
char *RightTrim(char *str); //处理右边的空格
char *LeftTrim(char *ptr); //处理左边的空格
SQLDA *select_dp;
};//---------------------------------------------------------------------------------------------------
QDBC::QDBC(char* cHostName, char* cUserName, char* cPassword, char* cDBoSerName, char cDBMode):B_QDBC(cHostName, cUserName, cPassword, cDBoSerName, cDBMode)
{
EXEC SQL WHENEVER SQLERROR DO sql_error();
}
//---------------------------------------------------------------------------------------------------
QDBC::~QDBC()
{
free_res();
//关闭连接
EXEC SQL COMMIT RELEASE;
}
//---------------------------------------------------------------------------------------------------
bool QDBC::Connect()
{
//连接数据库
//定义oracle变量
EXEC SQL BEGIN DECLARE SECTION;
char oHostName[20]; //主机名称或地址
char oUserName[20]; //登陆用户名
char oPassword[20]; //登陆密码
char oDBoSerName[20]; //数据库名称或者服务器名称
EXEC SQL END DECLARE SECTION;
strcpy(oHostName,HostName);
strcpy(oUserName,UserName);
strcpy(oPassword,Password);
strcpy(oDBoSerName,DBoSerName);// EXEC SQL CONNECT :oUserName IDENTIFIED BY :oPassword AT :oHostName USING :oDBoSerName;
EXEC SQL CONNECT :oUserName IDENTIFIED BY :oPassword USING :oDBoSerName;
if(sqlca.sqlcode==0)
{
ErrOut(Q_COMMD_OK);
Connected = true;
return(true);
}
else
ErrOut(Q_CONNT_ERROR);
return(false);
}
//---------------------------------------------------------------------------------------------------
int QDBC::ReturnRes(char *SqlQuary, int Mode)
{
// EXEC ORACLE OPTION (HOLD_CURSOR=YES);
EXEC ORACLE OPTION (MAXOPENCURSORS=1000);
// EXEC ORACLE OPTION (RELEASE_CURSOR=YES);
int rc=0;
//首先判断是否连接
if (!Connected)
{
ErrOut(Q_CONNT_ERROR);
return(-1);
}
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR SQLquare[1024]; //查询语句
EXEC SQL END DECLARE SECTION;
//初试化
memset((char *)SQLquare.arr,'\0',1024);
SQLquare.len=0; //分配选择描述区和绑定描述区
alloc_descriptors(MAX_ITEMS, MAX_VNAME_LEN, MAX_INAME_LEN);
//SQL语句赋值
strcpy((char *)SQLquare.arr,SqlQuary);
SQLquare.len = strlen(SqlQuary);
EXEC SQL PREPARE S FROM :SQLquare;
//定义游标 select * from v$open_cursors
//select * from v$open_cursor where USER_NAME like 'HTMAIL';
EXEC SQL DECLARE C SCROLL CURSOR FOR S;
EXEC SQL OPEN C USING DESCRIPTOR select_dp;
if (sqlca.sqlcode!=0)
{
ErrOut(Q_OTHER_ERROR);
rc = -1;
}
else
{
//select的时候
if (Mode==0)
{
rc=process_select_list();
}
//操作语句的时候
if (Mode==1)
{
RES.Fields=0;
RES.Count=0;
rc=0;
}
}
EXEC SQL COMMIT;
EXEC SQL CLOSE C;
free_res();
return(rc);
}
//---------------------------------------------------------------------------------------------------
bool QDBC::GetRES()
{
return(false);
}
//---------------------------------------------------------------------------------------------------
//打印错误
void QDBC::sql_error()
{
sprintf(errdetail,"%.*s",sqlca.sqlerrm.sqlerrml,sqlca.sqlerrm.sqlerrmc);
}
//---------------------------------------------------------------------------------------------------
void QDBC::alloc_descriptors(int size, int max_vname_len, int max_iname_len)
{
int i=0;
FreeRES();
select_dp=SQLSQLDAAlloc(0,size,max_vname_len,max_iname_len);
select_dp->N=MAX_ITEMS;
for (i=0;i<MAX_ITEMS;i++)
{
select_dp->I[i]=(short *)malloc(sizeof(short));
select_dp->V[i]=(char *)malloc(1);
}
}
1,用 socket 建立守候进程,等待客户端发来SQL语句,并且返回数据库数值
2,用PROC建立了一个类,并且用PROC预编译通过,现在出现一下问题因为 socket 使用的是 fork() 多进程编程,每次接收客户端发送来的SQL语句后,就建立一个新进程,但是每个进程执行完毕后游标不自动清空,所以接收没有几个就被占满了,出现一下语句:
ORA-01000: maximum open cursors exceeded但是,我的类里面明明给游标关闭了呀?一下就是类的全部内容,请各位大侠帮忙看看。
因为太长,我分段,都是连续的:/*-------------------------------------------------------------------------
类名称:QDBC
类功能:连接ORACLE数据库专用类
设计日:2004-7-16
设计者:邱洋(Q龙-QDragon)
邮箱:[email protected]
修改日期:2004-7-19
修改内容:绝对不能在头文件中加入 sqlcpr.h 这个函数声明文件 修改日期:2004-7-20
修改内容:有时候要也要将自己的头文件放在系统头文件的前面 修改日期:2004-7-30
修改内容:将 ReturnRes() 函数中 Mode==1 部分返回了 0,并且将 RES.Fields 和 RES.Count 赋值为 0
--------------------------------------------------------------------------*/
#include "../b_qdbc.hpp"
#include <setjmp.h>
#include <sqlcpr.h>
#include <sqlda.h>
#include <sqlca.h>
/////////////////////////////////////////////////////////////////////
#define MAX_ITEMS 100 //定义选择列表项和绑定变量的最大个数
#define MAX_VNAME_LEN 30 //定义选择列表项、绑定变量名称的最大长度
#define MAX_INAME_LEN 30 //定义指示变量名称的最大长度
/////////////////////////////////////////////////////////////////////class QDBC :public B_QDBC
{
public:
//构造函x数
QDBC(char* cHostName, char* cUserName, char* cPassword, char* cDBoSerName, char cDBMode);
~QDBC();
//操作函数
bool Connect(); //建立连接
bool Disconnect(); //断开连接
bool GetRES(); //取得资源(如果是MYSQL也一次取完--根据返回记录类)
int ReturnRes(char *SqlQuary, int Mode);//获取资源(Mode=0 是资料语句 Mode=1 是操作语句) private:
void sql_error();
void alloc_descriptors(int, int, int);
void set_bind_variables();
int process_select_list();
void free_res();
char *RightTrim(char *str); //处理右边的空格
char *LeftTrim(char *ptr); //处理左边的空格
SQLDA *select_dp;
};//---------------------------------------------------------------------------------------------------
QDBC::QDBC(char* cHostName, char* cUserName, char* cPassword, char* cDBoSerName, char cDBMode):B_QDBC(cHostName, cUserName, cPassword, cDBoSerName, cDBMode)
{
EXEC SQL WHENEVER SQLERROR DO sql_error();
}
//---------------------------------------------------------------------------------------------------
QDBC::~QDBC()
{
free_res();
//关闭连接
EXEC SQL COMMIT RELEASE;
}
//---------------------------------------------------------------------------------------------------
bool QDBC::Connect()
{
//连接数据库
//定义oracle变量
EXEC SQL BEGIN DECLARE SECTION;
char oHostName[20]; //主机名称或地址
char oUserName[20]; //登陆用户名
char oPassword[20]; //登陆密码
char oDBoSerName[20]; //数据库名称或者服务器名称
EXEC SQL END DECLARE SECTION;
strcpy(oHostName,HostName);
strcpy(oUserName,UserName);
strcpy(oPassword,Password);
strcpy(oDBoSerName,DBoSerName);// EXEC SQL CONNECT :oUserName IDENTIFIED BY :oPassword AT :oHostName USING :oDBoSerName;
EXEC SQL CONNECT :oUserName IDENTIFIED BY :oPassword USING :oDBoSerName;
if(sqlca.sqlcode==0)
{
ErrOut(Q_COMMD_OK);
Connected = true;
return(true);
}
else
ErrOut(Q_CONNT_ERROR);
return(false);
}
//---------------------------------------------------------------------------------------------------
int QDBC::ReturnRes(char *SqlQuary, int Mode)
{
// EXEC ORACLE OPTION (HOLD_CURSOR=YES);
EXEC ORACLE OPTION (MAXOPENCURSORS=1000);
// EXEC ORACLE OPTION (RELEASE_CURSOR=YES);
int rc=0;
//首先判断是否连接
if (!Connected)
{
ErrOut(Q_CONNT_ERROR);
return(-1);
}
EXEC SQL BEGIN DECLARE SECTION;
VARCHAR SQLquare[1024]; //查询语句
EXEC SQL END DECLARE SECTION;
//初试化
memset((char *)SQLquare.arr,'\0',1024);
SQLquare.len=0; //分配选择描述区和绑定描述区
alloc_descriptors(MAX_ITEMS, MAX_VNAME_LEN, MAX_INAME_LEN);
//SQL语句赋值
strcpy((char *)SQLquare.arr,SqlQuary);
SQLquare.len = strlen(SqlQuary);
EXEC SQL PREPARE S FROM :SQLquare;
//定义游标 select * from v$open_cursors
//select * from v$open_cursor where USER_NAME like 'HTMAIL';
EXEC SQL DECLARE C SCROLL CURSOR FOR S;
EXEC SQL OPEN C USING DESCRIPTOR select_dp;
if (sqlca.sqlcode!=0)
{
ErrOut(Q_OTHER_ERROR);
rc = -1;
}
else
{
//select的时候
if (Mode==0)
{
rc=process_select_list();
}
//操作语句的时候
if (Mode==1)
{
RES.Fields=0;
RES.Count=0;
rc=0;
}
}
EXEC SQL COMMIT;
EXEC SQL CLOSE C;
free_res();
return(rc);
}
//---------------------------------------------------------------------------------------------------
bool QDBC::GetRES()
{
return(false);
}
//---------------------------------------------------------------------------------------------------
//打印错误
void QDBC::sql_error()
{
sprintf(errdetail,"%.*s",sqlca.sqlerrm.sqlerrml,sqlca.sqlerrm.sqlerrmc);
}
//---------------------------------------------------------------------------------------------------
void QDBC::alloc_descriptors(int size, int max_vname_len, int max_iname_len)
{
int i=0;
FreeRES();
select_dp=SQLSQLDAAlloc(0,size,max_vname_len,max_iname_len);
select_dp->N=MAX_ITEMS;
for (i=0;i<MAX_ITEMS;i++)
{
select_dp->I[i]=(short *)malloc(sizeof(short));
select_dp->V[i]=(char *)malloc(1);
}
}
int QDBC::process_select_list()
{
int i, null_ok, precision, scale, j=0; //选择列表项,选择描述区
EXEC SQL DESCRIBE SELECT LIST FOR S INTO select_dp;
//设置选择列表项的实际个数
select_dp->N = select_dp->F;
if (select_dp->F<=0)
return(select_dp->F);
for (i=0;i<select_dp->F;i++)
{
//清除 T[i] 高位 null
SQLColumnNullCheck(0,(unsigned short *)&(select_dp->T[i]),(unsigned short *)&(select_dp->T[i]), &null_ok);
//设置数据长度
switch (select_dp->T[i])
{
case 1: //CHAR
break; case 2: //NUMBER
SQLNumberPrecV6(0,(unsigned int *)&(select_dp->L[i]),&precision,&scale);
if (precision == 0)
precision = 40;
select_dp->L[i] = precision + 2;
break; case 8: //LONG
select_dp->L[i] = 240;
break; case 11: //ROWID
select_dp->L[i] = 18;
break; case 12: //DATE
select_dp->L[i] = 9;
break; case 23: //RAW
break; case 24: //LONGRAW
select_dp->L[i] = 240;
break;
}
/*-显示标题部分,暂时注解--------------------------------
//初试化 title
memset(title,'\0',MAX_VNAME_LEN);
//选择列表项目名称
strncpy(title,select_dp->S[i],select_dp->C[i]);
printf("\t|%-.*s|",strlen(title),title);
-------------------------------------------------------*/ //为选择列表数据缓冲区重新分配内存
select_dp->V[i] = (char *)realloc(select_dp->V[i],select_dp->L[i]+1);
//所有都设置为CHAR类型
select_dp->T[i]=1;
}
//字段数和记录数赋值:
RES.Fields=select_dp->F; //字段数
i=0,j=0;
//开始获取内容
//清空数据
FreeRES();
EXEC SQL WHENEVER NOT FOUND DO BREAK;
for (;;)
{
//如果大于最大记录数就退出
if (j>=Q_MAX_RES)
break;
EXEC SQL FETCH C USING DESCRIPTOR select_dp;
if (sqlca.sqlcode!=0)
{
ErrOut(Q_OTHER_ERROR);
return(false);
}
//数据赋值
for (i=0;i<select_dp->F;i++)
{
sprintf(RES.ROWS[j][i],"%.*s",select_dp->L[i],select_dp->V[i]);
//处理字符串
strcpy(RES.ROWS[j][i],RightTrim(RES.ROWS[j][i]));
}
j++;
}
if (sqlca.sqlerrd[2]>Q_MAX_RES)
RES.Count = Q_MAX_RES;
else
RES.Count=sqlca.sqlerrd[2]; //记录数
return(RES.Count);
}
//----------------------------------------------------------------------------------------------
void QDBC::free_res()
{
//释放绑定变量和选择列表项所占内存
for (int i=0;i<MAX_ITEMS;i++)
{
if (select_dp->V[i]!=(char *)0)
free(select_dp->V[i]);
free(select_dp->I[i]);
}
//释放绑定描述区和选择描述区
SQLSQLDAFree(0,select_dp);
}
//----------------------------------------------------------------------------------------------
char *QDBC::RightTrim(char *ptr)
{
int k;
k=strlen(ptr);
while (k>0)
{
if(ptr[k]!=' ' && ptr[k]!='\t' && ptr[k]!=0)
break;
k--;
}
ptr[k+1]='\0';
return(ptr);
}
//----------------------------------------------------------------------------------------------
char *QDBC::LeftTrim(char *ptr)
{
return NULL; //暂不处理
}
可以得到数据 ,并且数据完全正确,可就是老是无法释放游标,如果是单进程,那么就产生一个游标,并且每次执行的时候老保持一个游标(用 select * from v$open_cursor语句察看),可是如果使用 fork() 多进程 ,则每个进程都有一个游标残留。