⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cursor.cpp

📁 在动态库中实现异步导出大数据量的oracle数据
💻 CPP
📖 第 1 页 / 共 3 页
字号:
#include "stdafx.h"

#define __OCICPP_INTERNAL_USE_

#include "Cursor.h"

/*! \class OCICPP::Cursor

  \brief Representation of a database cursor

  This class represents a database cursor, which is used to access a set or
  list of database rows from a single entity or a join of multiple entities.

  A cursor may be generate by issuing for example a 'SELECT'-statement, e.g.
  <pre>
  SELECT OWNER,CONSTRAINT_NAME,CONSTRAINT_TYPE,TABLE_NAME FROM USER_CONSTRAINTS
  </pre>

  An brief example:
  \code 
  Connection con;
  Connection::connect( tnsname, user, password, con);
  Cursor *csr = con.execQuery("SELECT OWNER,CONSTRAINT_NAME,CONSTRAINT_TYPE,TABLE_NAME FROM USER_CONSTRAINTS");
  while ( csr->fetch() ) {
    cout << csr->getStr( 0 ) << "." << csr->getStr( "CONSTRAINT_NAME" ) << endl;
  }
  \endcode

  In this example, a cursor is being generated, that can be used to retreive
  the four columns \c OWNER , \c CONSTRAINT_NAME , \c CONSTRAINT_TYPE ,
  \c TABLE_NAME from the \c USER_CONSTRAINTS table. The columns of this cursor
  may be accessed either by their ordering ( from left to right starting with 
  index \c 0 ) or by using their column name to index them (be sure to use
  capital letters when accessing them )
 */

/* Construction/Destruction related methods */

OCICPP::Cursor::Cursor(OCIEnv *env,OCISvcCtx *svc,OCIError *err,int prefetch,OCICPP::CursorType Type) {
	init(env,svc,err,prefetch,Type);
}

/*!
  Default Constructor: Create a cursor variable, which is not bound to any
  query (yet). A cursor create in such a manner can for example be used for
  Connection::execQuery(const string &,Cursor &,int)
*/
OCICPP::Cursor::Cursor() {
	envhp=0; svchp=0; stmthp=0; paramd=0; errhp=0; nCols=0;
	nulltext=default_null_text; row=0; cursorType=DEFAULT;
	curRow=0; prefetchRows=0; fetched=0; fetched_all=0;
}

void OCICPP::Cursor::init(OCIEnv *env,OCISvcCtx *svc,OCIError *err,int prefetch,OCICPP::CursorType Type) {
	envhp=env; svchp=svc; stmthp=0; paramd=0; errhp=err;curRow=0; fetched=0;
	prefetchRows=prefetch; nulltext=default_null_text; row=0; nCols=0; cursorType=Type;
	fetched_all=0;
	//Alloc statement handle
	if(cursorType!=NTABLE) {
		status=OCIHandleAlloc( (dvoid *) envhp, (dvoid **) &stmthp, OCI_HTYPE_STMT, (size_t) 0, (dvoid **) 0);
		if(status!=OCI_SUCCESS) throw OraError("Cursor: init(): Handle Alloc Failed.",OCICPPERROR);
	}
	Initialized=1;
}

/*!
  Destructor
 */
OCICPP::Cursor::~Cursor() {
	drop();	
}

/*!
  Clear the content of the cursor. This function may be used to free a cursor
  variable before reusing it again.
 */
void OCICPP::Cursor::drop() {
	if(!Initialized) return;
	map<string,OCIBind *>::const_iterator ci=binds.begin();
	while(ci!=binds.end()) {
		if(ci->second) OCIHandleFree(ci->second,OCI_HTYPE_BIND);
		*ci++;
		DEBUG(DLEV_DEBUG,"Bind nandle freed\n");
	} 
	binds.clear();
	for(int i=0;i<nCols;i++) {
		delete row[i];
	}
	cols_map.clear();
	delete row;
	
	/* We have no need to free cause it will be done in OraRefCur */
	if(stmthp && cursorType!=NTABLE) OCIHandleFree(stmthp,OCI_HTYPE_STMT);
	Initialized=0;
}

/* --------------------------------------------------- */

void OCICPP::Cursor::execute(int prefetch) {
	prefetchRows=prefetch;
	curRow=0; fetched=0; fetched_all=0; 
	for(int i=0;i<nCols;i++) delete row[i];
	cols_map.clear();
	delete row;
		
	if(cursorType==DEFAULT) {
		exec();
	} else {
		CHECKERR(errhp,OCIAttrGet(stmthp,OCI_HTYPE_STMT,(dvoid *) &stmtType,(ub4 *) 0,OCI_ATTR_STMT_TYPE,errhp));
	}
	DEBUG(DLEV_DEBUG,"execute(): stmtType=%d\n",stmtType);
	if(stmtType==OCI_STMT_SELECT) {
		describe();
		define();
	}
}

int OCICPP::Cursor::prepare(const std::string &sql) {
	DEBUG(DLEV_DEBUG,"Preparing statement\n");
	CHECKERR(errhp,OCIStmtPrepare(stmthp, errhp,(text *) sql.c_str() ,(ub4) strlen(sql.c_str()), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT));	
	CHECKERR(errhp,OCIAttrGet(stmthp,OCI_HTYPE_STMT,(dvoid *) &stmtType,(ub4 *) 0,OCI_ATTR_STMT_TYPE,errhp));
	return (int)stmtType;
}

void OCICPP::Cursor::exec() {
	DEBUG(DLEV_DEBUG,"Executing\n");
	if(stmtType==OCI_STMT_SELECT) {
		CHECKERR(errhp,OCIStmtExecute(svchp, stmthp,errhp,(ub4) 0,(ub4) 0, NULL, NULL, OCI_DEFAULT));
	} else {
		CHECKERR(errhp,OCIStmtExecute(svchp, stmthp,errhp,(ub4) 1,(ub4) 0, NULL, NULL, OCI_DEFAULT));
	}
}

unsigned int OCICPP::Cursor::execEx() {
	ub4 rows_ = 1;
	ub4 rowLength_ = sizeof(rows_);
	DEBUG(DLEV_DEBUG,"Executing\n");
	if(stmtType==OCI_STMT_SELECT) {
		CHECKERR(errhp,OCIStmtExecute(svchp, stmthp,errhp,(ub4)0,(ub4) 0, NULL, NULL, OCI_DEFAULT));
	} else {
		CHECKERR(errhp,OCIStmtExecute(svchp, stmthp,errhp,(ub4)1,(ub4) 0, NULL, NULL, OCI_DEFAULT));
		CHECKERR(errhp,OCIAttrGet(stmthp,(ub4) OCI_HTYPE_STMT, (ub4 *)&rows_, (ub4 *) &rowLength_,
				(ub4) OCI_ATTR_ROW_COUNT, (OCIError*) errhp));
//            DEBUG(DLEV_FATAL,"exec(): update rows = %d\n", rows_);
	}
	return (unsigned int) rows_;
}


void OCICPP::Cursor::describe() {
	DEBUG(DLEV_DEBUG,"Describing\n");
	CHECKERR(errhp,OCIAttrGet(stmthp,OCI_HTYPE_STMT,(dvoid *) &nCols,(ub4 *) 0,OCI_ATTR_PARAM_COUNT,errhp));
	row=new OraType*[nCols];
	for(int col=0;col<nCols;col++) {
		newCellByType(&(row[col]),stmthp,col);
	}
	if(nCols) haveResultSet=1;
	hashHead();
}
void OCICPP::Cursor::hashHead() {
	DEBUG(DLEV_DEBUG,"Mapping cols\n");
	for(int col=0;col<nCols;col++) {
		string attrName;
		getColName(col,attrName);
		cols_map[attrName]=col;
	}
}

void OCICPP::Cursor::define() {
	DEBUG(DLEV_DEBUG,"Defining output variables\n");
	for(int i=0;i<nCols;i++) {
		row[i]->define(stmthp,i);
	}
	haveResultSet=1;
}	
/* Binding func's */
void OCICPP::Cursor::bind(const std::string &par,char *buf,int buflen,short *isNull) {
	map<string,OCIBind *>::const_iterator ci=binds.find(par);
	if(ci==binds.end()) {
		binds[par]=0;
	}  //reuse handler ... 
	
	CHECKERR(errhp,OCIBindByName(stmthp,&(binds[par]),errhp,(CONST text *)par.c_str(),(sb4)strlen(par.c_str()),
								 (dvoid *)buf,(sb4)buflen,SQLT_STR,(dvoid *)isNull,(ub2 *)0,
								 (ub2 *)0,(ub4)0,(ub4 *)0,OCI_DEFAULT));
	DEBUG(DLEV_DEBUG,"Bind done.param=%s,val=%s\n",par.c_str(),buf);
}
void OCICPP::Cursor::bind(const std::string &par,const std::string &val,short *isNull) {
	map<string,OCIBind *>::const_iterator ci=binds.find(par);
	if(ci==binds.end()) {
		binds[par]=0;
	}  //reuse handler ... 
	CHECKERR(errhp,OCIBindByName(stmthp,&(binds[par]),errhp,(CONST text *)par.c_str(),(sb4)strlen(par.c_str()),
								 (dvoid *)val.c_str(),(sb4)strlen(val.c_str())+1,SQLT_STR,(dvoid *)isNull,(ub2 *)0,
								 (ub2 *)0,(ub4)0,(ub4 *)0,OCI_DEFAULT));
	DEBUG(DLEV_DEBUG,"Bind done.param=%s,val=%s\n",par.c_str(),val.c_str());
}

void OCICPP::Cursor::bind(const std::string &par,int &val,short *isNull) {
	map<string,OCIBind *>::const_iterator ci=binds.find(par);
	if(ci==binds.end()) {
		binds[par]=0;
	}  //reuse handler ... 
	CHECKERR(errhp,OCIBindByName(stmthp,&(binds[par]),errhp,(CONST text *)par.c_str(),(sb4)strlen(par.c_str()),
								 (dvoid *)&val,(sb4)sizeof(int),SQLT_INT,(dvoid *)isNull,(ub2 *)0,
								 (ub2 *)0,(ub4)0,(ub4 *)0,OCI_DEFAULT));
	DEBUG(DLEV_DEBUG,"Bind done.param=%s,val=%d\n",par.c_str(),val);
}

void OCICPP::Cursor::bind(const std::string &par,double &val,short *isNull) {	
	map<string,OCIBind *>::const_iterator ci=binds.find(par);
	if(ci==binds.end()) {
		binds[par]=0;
	}  //reuse handler ... 
	CHECKERR(errhp,OCIBindByName(stmthp,&(binds[par]),errhp,(CONST text *)par.c_str(),(sb4)strlen(par.c_str()),
								 (dvoid *)&val,(sb4)sizeof(double),SQLT_FLT,(dvoid *)isNull,(ub2 *)0,
								 (ub2 *)0,(ub4)0,(ub4 *)0,OCI_DEFAULT));
	DEBUG(DLEV_DEBUG,"Bind done.param=%s,val=%f\n",par.c_str(),val);
}

void OCICPP::Cursor::bind(const std::string &par,RowID &rowid,short *isNull) {
	map<string,OCIBind *>::const_iterator ci=binds.find(par);
	if(ci==binds.end()) {
		binds[par]=0;
	}  //reuse handler ... 
	OraRowID *rid=rowid.getRowID();
	CHECKERR(errhp,OCIBindByName(stmthp,&(binds[par]),errhp,(CONST text *)par.c_str(),(sb4)strlen(par.c_str()),
								 &(rid->rowid[curRow]),-1,SQLT_RDD,(dvoid *)isNull,(ub2 *)0,
								 (ub2 *)0,(ub4)0,(ub4 *)0,OCI_DEFAULT));
	DEBUG(DLEV_DEBUG,"Bind done.param=%s,val=ROWID\n",par.c_str());
}

void OCICPP::Cursor::bind(const std::string &par,Cursor &cur,short *isNull) {
	map<string,OCIBind *>::const_iterator ci=binds.find(par);
	if(ci==binds.end()) {
		binds[par]=0;
	}  //reuse handler ... 
	cur.init(envhp,svchp,errhp,1,REFCURSOR);
	CHECKERR(errhp,OCIBindByName(stmthp,&(binds[par]),errhp,(CONST text *)par.c_str(),(sb4)strlen(par.c_str()),
								 (dvoid *)&(cur.stmthp),(sb4)0,SQLT_RSET,(dvoid *)isNull,(ub2 *)0,
								 (ub2 *)0,(ub4)0,(ub4 *)0,OCI_DEFAULT));
	DEBUG(DLEV_DEBUG,"Bind done.param=%s,val=Cursor\n",par.c_str());
}

void OCICPP::Cursor::bind(const std::string &par,Lob &lob,short *isNull) {
	map<string,OCIBind *>::const_iterator ci=binds.find(par);
	if(ci==binds.end()) {
		binds[par]=0;
	}  //reuse handler ... 
	lob.init(envhp,svchp,errhp);
	CHECKERR(errhp,OCIBindByName(stmthp,&(binds[par]),errhp,(CONST text *)par.c_str(),(sb4)strlen(par.c_str()),
								 (dvoid *)&(lob.lob),(sb4)0,SQLT_BLOB,(dvoid *)isNull,(ub2 *)0,
								 (ub2 *)0,(ub4)0,(ub4 *)0,OCI_DEFAULT));
	DEBUG(DLEV_DEBUG,"Bind done.param=%s,val=Cursor\n",par.c_str());
}	



/* --------------------------------------*/

/*!
  Fetch the content of the cursor's next row(s) from the database server

  \return 0 if no new row is available
 */
bool OCICPP::Cursor::fetch() {
	unsigned tmp_fetched;
	canFetch=1;
	if(haveResultSet) {
		curRow++;
		if(curRow==fetched && fetched<prefetchRows) {
			canFetch=0;
		} else if(curRow==fetched || !fetched) {
			status=OCIStmtFetch(stmthp,errhp,(ub4) prefetchRows,OCI_FETCH_NEXT,OCI_DEFAULT); 
			tmp_fetched=fetched_all;
			CHECKERR(errhp,OCIAttrGet(stmthp,OCI_HTYPE_STMT,&fetched_all,0,OCI_ATTR_ROW_COUNT,errhp));
			fetched=fetched_all-tmp_fetched;
			DEBUG(DLEV_DEBUG,"fetched=%d\n",fetched);
			if(!fetched) {
				canFetch=0;
				DEBUG(DLEV_DEBUG,"No more rows\n");
			} else {
				canFetch=1;
				curRow=0;
			} 
		} 
	}
	return (canFetch==1)?true:false;
}

/* 	get<Type> functions */

/*! \fn int OCICPP::Cursor::getInt(const std::string &col,bool *isNull,const int *null_value) const
  Return an integer value from the column named \a col . Unless pointing to 0,
  \a *isNull is set to \c TRUE if the retreived value is NULL in the sence of
  the database server. A client-specific value to be returned may be supplied
  by having \a null_value point to this value.

  \sa void getInt(int,int &,bool *,const int *) const,
      int getInt(int,bool *,const int *) const,
      void getInt(const std::string &,int &,bool *,const int *) const

 */
/*! \fn int OCICPP::Cursor::getInt(int col,bool *isNull, const int *null_value) const
  Return an integer value from the column indexed by \a col . Unless pointing
  to 0, \a *isNull is set to \c TRUE if the retreived value is NULL in the
  sence of the database server. A client-specific value to be returned may be
  supplied by having \a null_value point to this value.

  \sa void getInt(int,int &,bool *,const int *) const,
      void getInt(const std::string &,int &,bool *,const int *) const,
      int getInt(const std::string &,bool *, const int *) const
 */


/*! \fn double OCICPP::Cursor::getDouble(const std::string &col,bool *isNull=0,const double *null_value=0)const
  Return a double value from the column named \a col . Unless pointing
  to 0, \a *isNull set to \c TRUE if a NULL-value is retreived in this way. The
  value returned to the application may be specified by having \a null_value
  pointing to it.

  \sa void getDouble(int,double &,bool *,const double *) const,
      double getDouble(int,bool *,const double *) const,
      void getDouble(const std::string &,double &,bool *,const double *) const
 */
/*! \fn double OCICPP::Cursor::getDouble(int col,bool *isNull, const double *null_value) const
  Return a double value from the column indexed by \a col . Unless pointing
  to 0, \a *isNull set to \c TRUE if a NULL-value is retreived in this way. The
  value returned to the application may be specified by having \a null_value
  pointing to it.

  \sa void getDouble(int,double &,bool *,const double *) const,
      void getDouble(const std::string &,double &,bool *,const double *) const,
      double getDouble(const std::string &,bool *, const double *) const

 */


/*! Retrieve content from column number \a col into the string \a str. If
  \a isNull is not pointing to 0, this boolean reflects, if the cell's content
  was NULL or not.

  \sa void getStr(const std::string &,std::string &,bool *) const,
      std::string getStr(const std::string &,bool *) const,
      std::string getStr(int,bool *) const
*/
void OCICPP::Cursor::getStr(int col,std::string &str,bool *isNull) const {
	if(!canFetch || col<0 || col>=nCols) throw OraError(CELL_NOT_EXISTS);
	if(row[col]->isNull(curRow)) {
		str.assign(nulltext);
		if (isNull) *isNull = true;
		return;
	}
	row[col]->getStr(str,curRow);
	if (isNull) *isNull = false;
}

/*!
  Retrieve a string value \a val from the column named \a colName out of the
  current cursor position. If \a isNull is not pointing to 0, it is set
  according to the returned value. 

  \sa void getStr(int,std::string &,bool *) const,
      string getStr(const std::string &,bool *) const,
      string getStr(int,bool *) const
 */
void OCICPP::Cursor::getStr(const std::string &colName,std::string &val,bool *isNull) const {
	map<string,int>::const_iterator iter=cols_map.find(colName);
	if(iter!=cols_map.end()) {
		getStr(iter->second,val,isNull);
	} else {
		std::cerr << " Cell is '" << colName << "'\n";
		throw OraError(CELL_NOT_EXISTS);
	}
}

/*! \fn string OCICPP::Cursor::getStr(int col,bool *isNull) const
  Convenience function to retreive a string value from the cursor's current
  position put of column \a col . If \a isNull is not pointing to 0, \a *isNull
  is set to \c TRUE if the value retreived in this way was NULL in the database

  \sa void getStr(const string &,string &,bool *) const,
      void getStr(int,string &,bool *) const,
      string getStr(const string &,bool *) const
*/
/*! \fn string OCICPP::Cursor::getStr(const string &col,bool *isNull=0)const
  Convenience function to retreive a string value from the cursor's current
  position put of column named \a colName . If \a isNull is not pointing to 0,
  \a *isNull is set to \c TRUE if the value retreived in this way was NULL in
  the database

  \sa void getStr(const string &,string &,bool *) const,
      void getStr(int,string &,bool *) const,
      string getStr(int,bool *) const
 */



/*!
  Read an integer value \a val from the column indexed by \a col . Unless
  pointing to 0, \a *isNull is set to \c TRUE if the retreived value is NULL in
  the sence of the database server. A client-specific value to be returned as 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -