📄 cursor.cpp
字号:
#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 \a val may be supplied by having \a null_value point to this value.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -