Files

868 lines
20 KiB
C++

// GZRsetPool.cpp: implementation of the CGZRsetPool class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "sp.h"
#include "GZRsetPool.h"
#include "TED.H"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CGZRsetPool::CGZRsetPool()
{
//IMPORTANT: to avoid memory fragmentation set this
//value to something higher than the highest amount used
//pool.SetSize(10);
//used to track how many were allocated
//in order to set the pool size adequately
m_nTotalAllocated=0;
//default is JET
m_bSQLServer=false;
//Added 08/03/2001 to hide errors on update
m_bSupressErrors=false;
m_bUseTransactions=false;
//TEST TEST TEST
pConnection=NULL;
}
CGZRsetPool::~CGZRsetPool()
{
//dump any allocated recordsets if any
Empty();
}
//return a free recordset
//sets nRSID to the unique serial number of this rs
//for identification when closing later
GZRset * CGZRsetPool::GetRS(CString strCallerInfo)
{
GZRset* rs;
int x;
x=GetFreeRecordsetID(false);
rs=(GZRset*)pool.GetAt(x);
ASSERT(rs!=NULL);
rs->Close();
rs->m_bExclusiveConnection=false;
TRACE("\r\n*******************************\r\n"
"[ %i ] - total recordsets in the pool.\r\n"
"*******************************\r\n"
,m_nTotalAllocated);
rs->m_bRSPRINT=false;
//added Sept 30th 2002
//ensures on a change of use transactions
//that previously allocated rs's are set correctly
//when first accessed
rs->m_bUseTransactions=m_bUseTransactions;
rs->SetErrMsg(strCallerInfo);
return rs;
}
//return a free recordset
//sets nRSID to the unique serial number of this rs
//for identification when closing later
GZRset * CGZRsetPool::GetRSPrint(CString strCallerInfo)
{
GZRset* rs;
int x;
x=GetFreeRecordsetID(true);
rs=(GZRset*)pool.GetAt(x);
ASSERT(rs!=NULL);
rs->Close();
rs->m_bExclusiveConnection=false;
TRACE("\r\n*******************************\r\n"
"[ %i ] - total recordsets in the pool.\r\n"
"*******************************\r\n"
,m_nTotalAllocated);
rs->m_bRSPRINT=true;
rs->SetErrMsg(strCallerInfo);
return rs;
}
//flag recordset nRSID as available
bool CGZRsetPool::ReleaseRS(int* nID)
{
GZRset* rs;
rs=(GZRset*)pool.GetAt(*nID);
ASSERT(rs!=NULL);
//close it up just in case,
//safe to call this repeatedly,
//it just returns if already closed
rs->Close();
//Throw the RS back in the pool
rs->m_bReserved=false;
return true;
}
//empty the pool
//(delete all recordset objects)
void CGZRsetPool::Empty()
{
int x;
GZRset* rs;
if(m_nTotalAllocated>0)
{
for(x=0;x<m_nTotalAllocated;x++)
{
rs=(GZRset*)pool.GetAt(x);
rs->Close();
delete rs;
}
m_nTotalAllocated=0;
}
//added March 22 2001 on a whim
pool.RemoveAll();
}
//RETURNS the pool objarray index value of a free
//recordset, also sets the recordset as in use
int CGZRsetPool::GetFreeRecordsetID(bool bPrint)
{
int x;
if(m_nTotalAllocated==0)//none made yet
{
rsGENERIC = new GZRset("Allocated First");
InitializeNewRS(rsGENERIC,bPrint);
x=pool.Add((CObject*)rsGENERIC);
//set this recordset's ID value
rsGENERIC->m_nID=x;
//Increment the recordsets allocated counter
m_nTotalAllocated++;
return x;
}
//there are some allocated, see if any are free
for(int y=0; y<m_nTotalAllocated; y++)
{
rsGENERIC=(GZRset*)pool.GetAt(y);
//rsGENERIC=pool.GetAt(y);
if(rsGENERIC->m_bReserved==false)//is it free for use?
{
rsGENERIC->m_bReserved=true;
return y;
}
}
//There are none free so we have to add one now
rsGENERIC = new GZRset("Allocated");
InitializeNewRS(rsGENERIC, bPrint);
x=pool.Add((CObject*)rsGENERIC);
//set this recordset's ID value
rsGENERIC->m_nID=x;
m_nTotalAllocated++;
//arbitrary test value
ASSERT(m_nTotalAllocated<50);
return x;
}
bool CGZRsetPool::InitializeNewRS(GZRset *rs,bool bPrint)
{
ASSERT(rs!=NULL);
//TEST TEST TEST
ASSERT(pConnection!=NULL);
rs->pTheConnection=pConnection;
//set initial connection strings here
rs->SetConnect(strConnectString);
//Set standard connection string here
rs->m_strLiveConnectString=m_strLiveConnectString;
//Set exclusive connection string here
rs->m_strLiveConnectStringExclusive=m_strLiveConnectStringExclusive;
//Set DEAD connect string: point to the empty database file
rs->m_strDeadConnectString=m_strDeadConnectString;
//query to execute against the empty database file
//to ensure the original connection gets closed
//to the live database file
rs->m_strCloseQuery=m_strCloseQuery;
//Take it out of the pool
rs->m_bReserved=true;
//Added May21 2001 SQL server stuff
rs->m_bSQLServer=m_bSQLServer;
//Added 08/03/2001
rs->m_bSupressErrors=m_bSupressErrors;
//added 09/30/2002
rs->m_bUseTransactions=m_bUseTransactions;
//This is now the first database call as of
//December 8 2000
rs->Close();
return true;
}
//Diagnostic routine
void CGZRsetPool::ShowAllOpenRS()
{
int x;
GZRset* rs;
CString strMsg;
if(m_nTotalAllocated>0)
{
strMsg.Format("Total recordsets allocated:%i\r\n",m_nTotalAllocated);
for(x=0;x<m_nTotalAllocated;x++)
{
rs=(GZRset*)pool.GetAt(x);
strMsg+=rs->m_bInUse ? "** RS IS ACTIVE **":".. RS NOT ACTIVE ..";
strMsg=strMsg+rs->GetRSInfo()+"\r\n"+rs->m_strLastQuery+"\r\n";
strMsg+="\r\n---------------------------------\r\n";
}
CTED d;
d.m_strText=strMsg;
d.DoModal();
}
else
AfxMessageBox("No recordsets in use");
}
void CGZRsetPool::StartConnection()
{
//create a pointer to a connection
//_ConnectionPtr pConnection = NULL;
try{
//instantiate it:
pConnection.CreateInstance(__uuidof(Connection));
//get connect string
_bstr_t strCnn(m_strLiveConnectString);
//open the connection
//this will THROW if the database is corrupted
pConnection->Open (strCnn, "", "", adConnectUnspecified);
DisplayProperties();
}
catch (_com_error &e)
{
CString cstrErrMsg,strEx;HRESULT hr=e.Error();
int nReason=0;
// get info from com error
_bstr_t bstrSource(e.Source());
_bstr_t bstrDescription(e.Description());
CString str((BSTR)bstrDescription);
//Decode error message from JET (hope it's in english)
//because Microsoft doesn't pass through the original jet error
//only the MDAC general error 80004005
if(str.Find("File Already in Use")!=-1)
nReason=1;//locked exclusive / no rights\
if(str.Find("The Microsoft Jet database engine cannot open the file '(unknown)'")!=-1)
nReason=1;//locked exclusive / no rights\
if(str.Find("Name Not Found")!=-1)
nReason=2;//file not found
if(str.Find("Unrecognized database format")!=-1)
nReason=3;//corrupt or not a database.
switch(nReason)
{
case 0://unknown error
strEx="";
break;
case 1://exclusive or no rights
strEx="Common causes for this error:\r\n"
"1) Insufficient rights to the database folder and file\r\n"
"(check that you have full access rights to the database folder)\r\n"
"\r\n"
"2) Database file is already open in exclusive only mode by another user or program.\r\n"
"(check if another program has the database open such as Access\r\n"
"in exclusive only mode)\r\n\r\n";
break;
case 2://file not found
strEx="Common causes for this error:\r\n"
"1) The wrong location has been specified for the database\r\n"
"2) The database file has been deleted\r\n"
"3) The database file has been renamed\r\n\r\n";
break;
case 3://corrupt / not a database
strEx="Common causes for this error:\r\n"
"1) The database file is not actually a database file\r\n"
"(someone renamed a non-database file to a database file name)\r\n"
"\r\n"
"2) The database file is damaged and needs to be repaired.\r\n"
"(See the AyaNova manual reference section:\r\n"
"\"Repairing the AyaNova Database\"\r\n"
"which has complete instructions on repairing\r\n"
"the database, the causes of database corruption\r\n"
"and how to prevent the problem from happening\r\n"
"again in future.)\r\n\r\n";
break;
}
cstrErrMsg.Format(
"AyaNova could not open the database file:\r\n"
"\r\n"
"%s\\scdata.sc\r\n"
"\r\n"
"The database driver gave the following reason:\r\n"
"%s\r\n"
"\r\n"
"%s"
"This program will now close...",m_strDBPATH,str,strEx);
TRACE("*************************************************\n");
TRACE("Exception thrown for classes generated by #import\n");
TRACE("\tCode = %08x\n", hr);
TRACE("\tCode Meaning = %s\n", e.ErrorMessage());
TRACE("\tSource = %s\n", (LPCTSTR) bstrSource);
TRACE("Description = %s\n", (LPCTSTR) bstrDescription);
TRACE("*************************************************\n");
#ifdef AYQB
cstrErrMsg.Format(
"AyaNova could not open the database file:\r\n\r\n"
"%sqbtrial.aya\r\n\r\n"
"This database file does not appear to be a AyaNova QBI trial edition\r\n"
"compatible database.\r\n\r\n"
"AyaNova will now close...",m_strDBPATH);
#endif
AfxMessageBox(cstrErrMsg);
PostQuitMessage(-1);//exit now before anything worse happens
return ;
}
catch (...)
{
TRACE("*** Unhandled exception ***");
//AfxMessageBox(m_strErrMsg);
PostQuitMessage(-1);//exit now before anything worse happens
return ;
}
}
//****************************************************
// compact the database through a jro object
//**********************************************
bool CGZRsetPool::Compact(bool bKeepOld)
{
bool status=true;
CString src,dest,tempfile;
CFileStatus fstat;
CWaitCursor wait;
//delete old one if exists
tempfile.Format("%sscdata.tmp",m_strDBPATH);
if(CFile::GetStatus(tempfile,fstat)==TRUE)//file exists
{
TRY
{
CFile::Remove( tempfile );
}
CATCH( CFileException, e )
{
status=false;
CString cstrErrMsg;
cstrErrMsg.Format("Error in Compact: %s cannot be removed",tempfile);
AfxMessageBox(cstrErrMsg);
}
END_CATCH
}
if(status==true)
{
src.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=%sscdata.sc;Jet OLEDB:Engine Type=5;",
m_strDBPATH);
dest.Format("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=%sscdata.tmp;Jet OLEDB:Engine Type=5;",
m_strDBPATH);
_bstr_t bstsrc(src);
_bstr_t bstdest(dest);
try
{
IJetEnginePtr jet(__uuidof(JetEngine));
jet->CompactDatabase(bstsrc, bstdest);
}
catch(_com_error &e)
{
status=false;
CString cstrErrMsg;
//get info from com error
_bstr_t bstrSource(e.Source());
_bstr_t bstrDescription(e.Description());
TRACE( "*************************************************\n");
TRACE( "Exception thrown for classes generated by #import\n");
TRACE( "\tCode = %081x\n", e.Error);
TRACE( "\tCode Meaning = %s\n",e.ErrorMessage());
TRACE( "\tSource = %s\n", (LPCTSTR) bstrSource);
TRACE( "Description = %s\n", (LPCTSTR) bstrDescription);
TRACE( "*************************************************\n");
cstrErrMsg.Format("Error in Compact: %s,\r\n%s",e.ErrorMessage(),(LPCTSTR) bstrDescription);
AfxMessageBox(cstrErrMsg);
}
catch(...)
{
status=false;
TRACE( "*** Unhandled exception ***" );
AfxMessageBox("Unhandled Error in Compact");
PostQuitMessage(-1);//exit now before anything worse happens
}
}
//Added. indexing can leave a 100+mb old file
//this way can delete it
if(bKeepOld)
{
//copy mdb over old
src.Format("%sscdata.sc",m_strDBPATH);
dest.Format("%sscdata.old",m_strDBPATH);
status=CopyFile(src.GetBuffer(100),dest.GetBuffer(100));
}
if(status==true)
{
src.Format("%sscdata.tmp",m_strDBPATH);
dest.Format("%sscdata.sc",m_strDBPATH);
status=CopyFile(src.GetBuffer(100),dest.GetBuffer(100));
}//if status==true
//delete gz1
tempfile.Format("%sscdata.tmp",m_strDBPATH);
if(CFile::GetStatus(tempfile,fstat)==TRUE)//file exists
{
TRY
{
CFile::Remove( tempfile );
}
CATCH( CFileException, e )
{
status=false;
CString cstrErrMsg;
cstrErrMsg.Format("Error at end of Compact: %s cannot be removed\r\nOtherwise compact OK",tempfile);
AfxMessageBox(cstrErrMsg);
}
END_CATCH
}
return status;
}
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//*******************************************
//copy a file, overwrite dest if exists
bool CGZRsetPool::CopyFile(char *src, char *dest)
{
CFile sourceFile;
CFile destFile;
CFileException ex;
CString tempfile;
// open the source file for reading
if (!sourceFile.Open(src,
CFile::modeRead | CFile::shareDenyWrite, &ex))
{
// complain if an error happened
// no need to delete the ex object
TCHAR szError[1024];
ex.GetErrorMessage(szError, 1024);
CString errormsg;
errormsg.Format("Error copying file %s to %s\r\n The error was: %s",src,dest,szError);
AfxMessageBox(errormsg);
return false;
}
else
{
if (!destFile.Open(dest, CFile::modeWrite |
CFile::shareExclusive | CFile::modeCreate, &ex))
{
TCHAR szError[1024];
ex.GetErrorMessage(szError, 1024);
CString errormsg;
errormsg.Format("Error copying file %s to %s\r\n The error was: %s",src,dest,szError);
AfxMessageBox(errormsg);
sourceFile.Close();
return false;
}
BYTE buffer[4096];
DWORD dwRead;
// Read in 4096-byte blocks,
// remember how many bytes were actually read,
// and try to write that many out. This loop ends
// when there are no more bytes to read.
do
{
dwRead = sourceFile.Read(buffer, 4096);
destFile.Write(buffer, dwRead);
}
while (dwRead > 0);
// Close both files
destFile.Close();
sourceFile.Close();
}
return true;
}
bool CGZRsetPool::GoExclusive()
{
try{
if(pConnection->GetState()==adStateOpen)
pConnection->Close();
//get connect string
_bstr_t strCnn(m_strLiveConnectStringExclusive);
//open the connection
pConnection->Open (strCnn, "", "", adConnectUnspecified);
}
catch (_com_error &e)
{
CString cstrErrMsg;
// get info from com error
_bstr_t bstrSource(e.Source());
_bstr_t bstrDescription(e.Description());
TRACE("*************************************************\n");
TRACE("Exception thrown for classes generated by #import\n");
TRACE("\tCode = %081x\n", e.Error);
TRACE("\tCode Meaning = %s\n", e.ErrorMessage());
TRACE("\tSource = %s\n", (LPCTSTR) bstrSource);
TRACE("Description = %s\n", (LPCTSTR) bstrDescription);
TRACE("*************************************************\n");
cstrErrMsg.Format("At GoExclusive access (all other users out)\r\n %s,\r\n%s", e.ErrorMessage(), (LPCTSTR) bstrDescription);
//cstrErrMsg.Format("%s: %s,\r\n%s",m_strErrMsg, e.ErrorMessage(), (LPCTSTR) bstrDescription);
AfxMessageBox(cstrErrMsg);
return false;
}
catch (...)
{
TRACE("*** Unhandled exception ***");
//AfxMessageBox(m_strErrMsg);
PostQuitMessage(-1);//exit now before anything worse happens
return false;
}
return true;
}
bool CGZRsetPool::GoShared()
{
try{
if(pConnection->GetState()==adStateOpen)
pConnection->Close();
//get connect string
_bstr_t strCnn(m_strLiveConnectString);
//open the connection
pConnection->Open (strCnn, "", "", adConnectUnspecified);
}
catch (_com_error &e)
{
CString cstrErrMsg;
// get info from com error
_bstr_t bstrSource(e.Source());
_bstr_t bstrDescription(e.Description());
TRACE("*************************************************\n");
TRACE("Exception thrown for classes generated by #import\n");
TRACE("\tCode = %081x\n", e.Error);
TRACE("\tCode Meaning = %s\n", e.ErrorMessage());
TRACE("\tSource = %s\n", (LPCTSTR) bstrSource);
TRACE("Description = %s\n", (LPCTSTR) bstrDescription);
TRACE("*************************************************\n");
cstrErrMsg.Format("At GoShared()\r\n%s,\r\n%s\r\n", e.ErrorMessage(), (LPCTSTR) bstrDescription);
//cstrErrMsg.Format("%s: %s,\r\n%s",m_strErrMsg, e.ErrorMessage(), (LPCTSTR) bstrDescription);
AfxMessageBox(cstrErrMsg);
return false;
}
catch (...)
{
TRACE("*** Unhandled exception ***");
//AfxMessageBox(m_strErrMsg);
PostQuitMessage(-1);//exit now before anything worse happens
return false;
}
return true;
}
void CGZRsetPool::Disconnect()
{
if(pConnection->GetState()==adStateOpen)
pConnection->Close();
}
//DIAGNOSIS Class for messing about with
//connection and other properties
//not actually used by the program
void CGZRsetPool::DisplayProperties()
{
PropertiesPtr pPrpLoop = NULL;
_variant_t vtIndex;
_variant_t propValue;
vtIndex.vt = VT_I2;
_variant_t vtOne;
vtOne.vt=VT_I4;
vtOne.lVal=1;
CString strName;
pPrpLoop=pConnection->GetProperties();
//pConnection->GetProperties()->GetItem()->Value=(_variant_t)1;
for (int intProperties = 0; intProperties < (int)pPrpLoop->
GetCount(); intProperties++)
{
vtIndex.iVal = intProperties;
propValue = pPrpLoop->GetItem(vtIndex)->Value;
strName=(LPCSTR) pPrpLoop->GetItem(vtIndex)->GetName();
if(strName=="Jet OLEDB:Transaction Commit Mode")
{
pPrpLoop->GetItem(vtIndex)->Value=vtOne;
break;
}
}
/*
#ifdef _DEBUG
propValue = pPrpLoop->GetItem(vtIndex)->Value;
ASSERT(propValue.iVal==1);
#endif
*/
}
//Get datbase properties for tech support
//displayed under help->About->Support info...
void CGZRsetPool::GetDBProps()
{
try{
if(pConnection->GetState()!=adStateOpen)
return;
//SET All version variables
m_strADOVersion = (LPCSTR) pConnection->Version;
m_strDBMSName = (LPCSTR) (_bstr_t)
pConnection->Properties->GetItem("DBMS Name")->Value;
m_strDBMSVersion= (LPCSTR) (_bstr_t) pConnection->
Properties->GetItem("DBMS Version")->Value;
m_strOLEDbVersion=(LPCSTR) (_bstr_t)
pConnection->Properties->GetItem("OLE DB Version")->Value;
m_strProviderName=(LPCSTR) (_bstr_t)
pConnection->Properties->GetItem("Provider Name")->Value;
m_strProviderVersion=(LPCSTR) (_bstr_t)
pConnection->Properties->GetItem("Provider Version")->Value;
/* m_strDriverVersion=(LPCSTR) (_bstr_t)
pConnection->Properties->GetItem("Driver Name")->Value;
m_strDriverName=(LPCSTR) (_bstr_t)
pConnection->Properties->GetItem("Driver Version")->Value;
m_strDriverODBCVersion=(LPCSTR) (_bstr_t)
pConnection->Properties->GetItem("Driver ODBC Version")->Value;
*/
}
catch (_com_error &e)
{
CString cstrErrMsg;
// get info from com error
_bstr_t bstrSource(e.Source());
_bstr_t bstrDescription(e.Description());
TRACE("*************************************************\n");
TRACE("Exception thrown for classes generated by #import\n");
TRACE("\tCode = %081x\n", e.Error);
TRACE("\tCode Meaning = %s\n", e.ErrorMessage());
TRACE("\tSource = %s\n", (LPCTSTR) bstrSource);
TRACE("Description = %s\n", (LPCTSTR) bstrDescription);
TRACE("*************************************************\n");
cstrErrMsg.Format("Error: Can't fetch database driver information.\r\n\r\nExact error is:\r\n%s", (LPCTSTR) bstrDescription);
return ;
}
catch (...)
{
TRACE("*** Unhandled exception ***");
//AfxMessageBox(m_strErrMsg);
return ;
}
}
//Added 08/03/2001 to selective turn off error
//warnings in gzrset to accomodate updates
//so users don't freak out
void CGZRsetPool::SupressErrors(bool bNoErrors)
{
m_bSupressErrors=bNoErrors;
int x;
GZRset* rs;
if(m_nTotalAllocated>0)
{
for(x=0;x<m_nTotalAllocated;x++)
{
rs=(GZRset*)pool.GetAt(x);
rs->m_bSupressErrors=m_bSupressErrors;
}
}
}