📄 bfile.cpp
字号:
#define __OCICPP_INTERNAL_USE_
#include "BFile.h"#include "OraError.h"
/*! \class OCICPP::BFile \brief Binary external Files within the Oracle Server's filesystem BFiles are a mean of representing large objects within the Oracle Server. Alternatives are Lob and TLob. The main difference between BFiles od the one side and Lobs and TLobs on the other is, that the BFile does not reside within the database's tablespaces (whereas Lobs and TLobs do). A BFile is located within the server's filesystem and thus has to be accessed there. Storing data externally has some consequences: \arg The operating system is responsible for storing these files \arg The is no way the Oracle Server can preserve these files \arg Since there is a maximum number of open file handles, one can never be sure to have access to a BFile, even if it exists \arg BFiles are (currently?) read-only On the other hand, there are some advantages: \arg The BFile does not populate the database tables (which may resolve in smaller databases) \arg BFiles are a mean of separating classical database content (in terms of entities that have a relation) from multimedia data (which typically is a rather large amount of data) Oracle states, that there is hardly any measurable performace difference between the large-object datatypes Lob, TLob and BFile, which leaves the decission of the type to be used to the user again. However, current policy seems to discourage the usage of BFiles. However, they can be very useful (according to the documentation writters humble opinion) if used carefully (and even reduce work). Imagine a database storing mainly textual data, where additionally some images or even audio- or video-sequences are incorporated. Lets again assume that the whole application is designed in client-server architecture, so that there is a big database which may be accessed from (many, perhaps browser) clients. BFiles then offer the capability to map data not stored within the database throught the Oracle-Layer to the client, so that there is no need to code a broker of any kind - this leaves one backend less. Let's look, if there's a Video-Archive identified by \c ZUSE and retreive the length of the BFILE-column called \b DATA (Error-Handling within this example is admittedly a little too rought...) \code using namespace OCICPP; int len = 0; try { Cursor cur; con->execQuery( "select * from MM_ARCHIVE WHERE TYPE='V' and ID='ZUSE'", cur ); if ( cur.fetch() ) { BFile bfile; cur.getFILE( "DATA", bfile ); bfile.open(); len = bfile.getLen(); bfile.close(); bfile.drop(); } cur.drop(); } catch ( OraError ) { } \endcode For additional information on how to create BFILE entities within the database, please refer to the Oracle Server Documentation (\b BFILENAME and \b CREATE \b DIRECTORY ). *//*! Construct an unbound bfile entity. */OCICPP::BFile::BFile():type(OCICPP::BFILE) { init(0,0,0);}OCICPP::BFile::BFile(OCISvcCtx *svcctx,OCILobLocator *lob_desc,OCIError *err): type(OCICPP::BFILE) { init(svcctx,lob_desc,err);}void OCICPP::BFile::init(OCISvcCtx *svcctx,OCILobLocator *lob_desc,OCIError *err) { boolean flg; svchp=svcctx; lob=lob_desc; errhp=err; offset=1; needLobFree=false; if(svchp && errhp) { DEBUG(DLEV_DEBUG,"Obtaining BFile len\n"); CHECKERR(errhp,OCILobFileExists(svchp,errhp,lob,&flg)); if(flg==FALSE) { throw OraError("OCICCPLIB: File not exist on server",OCICPPERROR); } CHECKERR(errhp,OCILobGetLength(svchp,errhp,lob,(ub4 *)&len)); DEBUG(DLEV_DEBUG,"BFile len is %d\n",len); } else { len=0; }}void OCICPP::BFile::init(OCIEnv *envhp,OCISvcCtx *svcctx,OCIError *err, const string &dir,const string &fname) { boolean flg; svchp=svcctx; errhp=err; offset=1; needLobFree=true; if(envhp && svchp && errhp) { DEBUG(DLEV_DEBUG,"Creating BFILE\n"); if(OCIDescriptorAlloc(envhp,(void **)&lob,OCI_DTYPE_FILE,0,0)!=OCI_SUCCESS) { throw OraError("OCICPPLIB: Cannot make new BFILE: Handle Allocation failed",OCICPPERROR); } CHECKERR(errhp, OCILobFileSetName(envhp,errhp,&lob, (OraText*)const_cast<char *>(dir.c_str()), dir.size(), (OraText *)const_cast<char *>(fname.c_str()), fname.size())); CHECKERR(errhp,OCILobFileExists(svchp,errhp,lob,&flg)); if(flg==FALSE) { throw OraError("OCICCPLIB: File not exist on server",OCICPPERROR); } CHECKERR(errhp,OCILobGetLength(svchp,errhp,lob,(ub4 *)&len)); DEBUG(DLEV_DEBUG,"BFile len is %d\n",len); } else { len=0; }}/*! Destruct a bfile entity. */OCICPP::BFile::~BFile() { /* nothing to be done yet all real work is in ~Cursor See TODO about how it should work .. */ drop();}/*! Drop a BFile entity. The Oracle Descriptior is freed on demand leaving the BFile instance ready for being reused. */void OCICPP::BFile::drop() { if(needLobFree) { OCIDescriptorFree(lob,OCI_DTYPE_FILE); }}/*! Set the position for reading/writing within a bfile. \param dir may be \b OCICPP::LOB_SET, \b OCICPP::LOB_CUR or \b OCICPP::LOB_END . \arg LOB_SET \a new_offset from begining of the BFile. \a offset may not be greater than Bfile's length ( getLen() ). \arg LOB_CUR modifies the access point within the BFile relative to the current position. \a current position \a + \a offset may not exceed the BFile's length \arg LOB_END sets the position from the end of the BFile. \param new_offset is the new distance relative to the given direction \a dir*/void OCICPP::BFile::seek(unsigned new_offset,OCICPP::LobDirection dir) { if((!len && new_offset>0) || ((dir==OCICPP::LOB_END ||dir==OCICPP::LOB_SET) && new_offset>len) || (dir==OCICPP::LOB_CUR && (new_offset+offset-1)>len)) { throw OraError("OCICPPLIB: Cannot seek: offset out of range",OCICPPERROR); } if(dir==OCICPP::LOB_SET) offset=new_offset+1; else if(dir==OCICPP::LOB_END) offset=len-new_offset+1; else if(dir==OCICPP::LOB_CUR) offset=offset+new_offset; else throw OraError("OCICPPLIB: Cannot seek: Unknown direction",OCICPPERROR);}/*! Retuns the current position from the start of the BFile. For this position, the inequation 0 <= tell() < getLen() holds. */unsigned OCICPP::BFile::tell() { return offset-1;}/*! Open a BFile. Before accessing, such a BFile has to be opened. Please keep in mind, that there is maximum number of simultaneously opened file handles withing the Oracle Server process. */void OCICPP::BFile::open() { CHECKERR(errhp,OCILobFileOpen(svchp,errhp,lob,OCI_FILE_READONLY));}/*! Close a previously opened BFile. This operation sets one file handle free again on the Oracle Server again. */void OCICPP::BFile::close() { CHECKERR(errhp,OCILobFileClose(svchp,errhp,lob));}/*! Read a sequence of \a buf_len bytes from the BFile into the buffer \a buf. The amount of bytes actually transfered is being returned. */unsigned OCICPP::BFile::read(void * buf,int buf_len) { unsigned off; unsigned actread=buf_len; off=offset; CHECKERR(errhp,OCILobRead(svchp,errhp,lob,(ub4 *)&actread,(ub4)off,buf,(ub4)buf_len,0, (sb4 (*)(dvoid *,dvoid *, ub4, ub1)) 0,(ub2) 0, (ub1) SQLCS_IMPLICIT)); offset+=actread; return actread;}/*! Retreive the total amount of data stored within this BFile. */unsigned OCICPP::BFile::getLen() const { return len;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -