campo-sirio/servers/odbc/server.cpp
guy c4ac448443 Servers
git-svn-id: svn://10.65.10.50/trunk@5855 c028cbd2-c16b-5b4b-a496-9718f37d4682
1998-01-07 10:17:26 +00:00

1181 lines
26 KiB
C++
Executable File
Raw Blame History

#include "StdAfx.h"
#include "errno.h"
#include "iserrors.h"
#include "connect.h"
#include "server.h"
#include "tracing.h"
#ifndef NO_MFC
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#endif
// @doc INTERNAL
// @rdesc Ritorna il valore corrispondente alla chiave appartenente
// ad una sezione del file di configurazione
static CString GetIniString(LPCSTR sec, // @parm Sezione
LPCSTR key, // @parm Chiave
LPCSTR def) // @parm Valore di default
{
// Nome del file .ini
static CString m_strIniFile;
// Lunghezza massima di un nome di directory
// o di un valore del file .ini
const DWORD dwSize = _MAX_DIR + 1;
// Costruisce il nome del file .ini se necessario
if (m_strIniFile.IsEmpty())
{
GetCurrentDirectory(dwSize, m_strIniFile.GetBuffer(dwSize));
m_strIniFile.ReleaseBuffer();
m_strIniFile += "\\prawin.ini";
}
// Legge il valore della chiave nella sezione specificata
CString tmp;
char* buf = tmp.GetBuffer(dwSize);
GetPrivateProfileString(sec, key, def, buf, dwSize, m_strIniFile);
tmp.ReleaseBuffer();
return tmp;
}
// @doc INTERNAL
// @class TFileInfo | Informazioni generali su di un file
//
// @base public | CObject
class TFileInfo : public CObject
// @author:(INTERNAL) Guido
// @access:(INTERNAL) Private Member
{
// @cmember:(INTERNAL) Nome del file
CString m_strName;
// @cmember:(INTERNAL) Nome del data source
CString m_strDataSource;
// @cmember:(INTERNAL) Descrizione del file
CString m_strDescription;
public:
// @cmember Ritorna il nome del file
const CString& GetName() const
{ return m_strName; }
// @cmember Ritorna il nome del data source
const CString& GetDataSource() const
{ return m_strDataSource; }
// @cmember Ritorna la descrizione del file
const CString& GetDescription() const
{ return m_strDescription; }
// @cmember Setta il nome del file
void SetName(LPCSTR sName)
{ m_strName = sName; }
// @cmember Setta il nome del data source
void SetDataSource(LPCSTR sDataSource)
{ m_strDataSource = sDataSource; }
// @cmember Setta la descrizione
void SetDescription(LPCSTR sDescription)
{ m_strDescription = sDescription; }
// @cmember Costruttore
TFileInfo() { }
// @cmember Distruttore
virtual ~TFileInfo() { }
};
// @doc INTERNAL
// @class TDataSources | Informazioni generali sui file
//
// @base public | CObject
class TDataSources : public CObject
// @author:(INTERNAL) Guido
// @access:(INTERNAL) Private Member
{
// @cmember:(INTERNAL) Motore di database DAO
CdbDBEngine m_dbEngine;
// @cmember:(INTERNAL) Nome del database principale
CString m_strDatabase;
// @cmember:(INTERNAL) Stringa di connsessione ODBC
CString m_strConnect;
// @cmember:(INTERNAL) Si tratta di una vera connessione ODBC
BOOL m_bODBC;
// @cmember:(INTERNAL) Elenco delle informazioni sui file
CMap<CString,LPCSTR,TFileInfo*,TFileInfo*> m_FileInfo;
// @cmember:(INTERNAL) Elenco dei database aperti
CMap<CString,LPCSTR,CdbDatabase*,CdbDatabase*> m_Databases;
protected:
// @cmember Carica tutte le descrizioni dei file
BOOL FillFileInfo();
// @cmember Ritorna le informazioni su di un file
const TFileInfo& GetFileInfo(int nLogicNumber) const;
// @cmember Costruisce il nome del database di un datasource
CString BuildDatabaseName(LPCSTR sName, int nFirm) const;
// @cmember Ritorna il database corrispondente ad un datasource
CdbDatabase* GetDatabase(LPCSTR sName, int nFirm);
// @cmember Ritorna il nome della tabella di un file
CString GetTableName(int nFirm, int nLogicNumber) const;
public:
// @cmember Ritorna TRUE se si tratta di una connessione ODBC
BOOL IsODBC() const { return m_bODBC; }
// @cmember Verifica l'esistenza di un datasource
BOOL TestDataSource(LPCSTR sName, int nFirm) const;
// @cmember Ritorna database e nome di un file
CdbDatabase* GetDataSource(int nFirm, int nLogicNum,
CString& strTableName);
// @cmember Toglie un riferimento al database
void ReleaseDataSource(int nFirm, int nLogicNum);
// @cmember Verifica la corretta inizializzazione
BOOL IsOk() const
{ return !m_FileInfo.IsEmpty(); }
// @cmember Costruttore
TDataSources();
// @cmember Distruttore
virtual ~TDataSources();
};
// @mfunc Costruisce il nome del database associato ad un
// determinato data source se <p sName> vale FIRM
// lo trasforma nel codice ditta corrispondente
// a <p nFirm>, es: 00883
CString TDataSources::BuildDatabaseName(
LPCSTR sName, // @parm Nome del data source
int nFirm) const // @parm Codice della ditta
{
CString strDataSource = m_strDatabase;
if (IsODBC())
{
// In ODBC esiste un unico database ad un livello
}
else
{
CString strName(sName);
if (strName == "FIRM")
strName.Format("%05dA", nFirm);
if (!strName.IsEmpty())
{
strDataSource += '\\';
strDataSource += strName;
}
}
return strDataSource;
}
// @mfunc Verifica l'esistenza di un data source
BOOL TDataSources::TestDataSource(
LPCSTR sName, // @parm Nome del data source
int nFirm) const // @parm Codice della ditta
{
CString strDataSource = BuildDatabaseName(sName, nFirm);
BOOL bOk = TRUE;
try
{
CdbDBEngine dbEngine;
dbEngine.OpenDatabase(strDataSource,
FALSE, FALSE,
m_strConnect);
}
catch(...)
{
bOk = FALSE;
}
return bOk;
}
// @mfunc Apre il database corrispondenete ad un data source
CdbDatabase* TDataSources::GetDatabase(
LPCSTR sName, // @parm Nome del data source
int nFirm) // @parm Codice della ditta
{
CString strDataSource = BuildDatabaseName(sName, nFirm);
CdbDatabase* pDatabase;
BOOL ok = m_Databases.Lookup(strDataSource, pDatabase);
if (!ok)
{
pDatabase = new CdbDatabase;
try
{
*pDatabase = m_dbEngine.OpenDatabase(strDataSource,
FALSE, FALSE,
m_strConnect);
m_Databases.SetAt(strDataSource, pDatabase);
}
catch(...)
{
delete pDatabase;
pDatabase = NULL;
}
}
return pDatabase;
}
// @mfunc Ritorna le informazioni sul file <p nLogicNumber>
const TFileInfo& TDataSources::GetFileInfo(int nLogicNumber) const
{
char codice[16]; itoa(nLogicNumber, codice, 10);
TFileInfo* fi;
BOOL ok = m_FileInfo.Lookup(codice, fi);
ASSERT(ok);
return *fi;
}
// @mfunc Ritorna il nome della tabella SQL contenete i dati
// del file ISAM <p nLogicNumber>
CString TDataSources::GetTableName(int nFirm, int nLogicNumber) const
{
const TFileInfo& fi = GetFileInfo(nLogicNumber);
CString strName;
if (IsODBC())
{
strName = fi.GetDataSource();
if (strName == "FIRM")
strName.Format("%05dA", nFirm);
strName += '_';
strName += fi.GetName();
}
else
strName = fi.GetName();
return strName;
}
// @mfunc Carica le informazioni relative a tutti i file ISAM
BOOL TDataSources::FillFileInfo()
{
CdbDatabase* pDatabase = GetDatabase("", 0);
if (pDatabase)
{
try
{
CdbRecordset rstDir = pDatabase->OpenRecordset("DIR", dbOpenDynaset);
COleVariant oleVariant;
for (rstDir.MoveFirst(); !rstDir.GetEOF(); rstDir.MoveNext())
{
oleVariant = rstDir.GetField("CODICE");
TFileInfo* fi = new TFileInfo;
m_FileInfo.SetAt((LPCSTR)oleVariant.pbVal, fi);
oleVariant = rstDir.GetField("NOME");
fi->SetName((LPCSTR)oleVariant.pbVal);
oleVariant = rstDir.GetField("SORGENTE");
fi->SetDataSource((LPCSTR)oleVariant.pbVal);
oleVariant = rstDir.GetField("DESCR");
fi->SetDescription((LPCSTR)oleVariant.pbVal);
}
}
catch(...)
{
pDatabase = NULL;
}
}
return pDatabase != NULL;
}
// @mfunc Ritorna il database ed il nome
CdbDatabase* TDataSources::GetDataSource(int nFirm, int nLogicNumber,
CString& strTableName)
{
const TFileInfo& fi = GetFileInfo(nLogicNumber);
const CString& strDataSource = fi.GetDataSource();
strTableName = GetTableName(nFirm, nLogicNumber);
return GetDatabase(strDataSource, nFirm);
}
// @mfunc Chiude un database inutilizzato
// Per il momemnto non si sa come implementarla
void TDataSources::ReleaseDataSource(int nFirm, int nLogicNumber)
{
// TODO:
}
// @mfunc Costruttore del'insieme dei data source
TDataSources::TDataSources()
{
const char* const odbc = "ODBC";
m_dbEngine.SetDefaultUser(GetIniString(odbc, "User", odbc));
m_dbEngine.SetDefaultPassword(GetIniString(odbc, "Pwd", odbc));
m_strDatabase = GetIniString(odbc, "Database", odbc);
m_strConnect = GetIniString(odbc, "Connect", odbc);
m_bODBC = m_strConnect.Mid(0, 4) == odbc;
FillFileInfo();
}
// @mfunc Distruttore del'insiemde dei data source
TDataSources::~TDataSources()
{
POSITION pos; // Posizione corrente nella lista
CString strKey; // Chiave dell'elemento corrente della lista
// Vuota la lista dei database
for (pos = m_Databases.GetStartPosition(); pos; )
{
CdbDatabase* pDatabase; // Database corrente
m_Databases.GetNextAssoc(pos, strKey, pDatabase);
pDatabase->Close();
delete pDatabase;
}
m_Databases.RemoveAll();
// Vuota la lista delle informazioni sui file
for (pos = m_FileInfo.GetStartPosition(); pos; )
{
TFileInfo* pFileInfo; // File corrente
m_FileInfo.GetNextAssoc(pos, strKey, pFileInfo);
delete pFileInfo;
}
m_FileInfo.RemoveAll();
}
/////////////////////////////////////////////////////////////////////////////
// TTableDef
class TTableDef : public CObject
{
CdbDatabase* m_db;
CString m_strTableName;
CdbRecordset m_Dynaset;
clock_t m_tModifyTime;
int m_nReferences;
CMap<CString,LPCSTR,DWORD,DWORD> m_Locks;
DWORD m_dwExclusiveLocker;
protected:
friend class TTableDefPool;
int AddReference() { return ++m_nReferences; }
int RemoveReference() { return --m_nReferences; }
void ZeroReferences() { m_nReferences = 0; }
public:
BOOL IsChangedSince(clock_t t) const
{ return t <= m_tModifyTime; }
CdbDatabase& GetDatabase() { return *m_db; }
const CString& GetTableName() { return m_strTableName; }
CdbTableDef GetTableDef();
CdbRecordset& GetDynaset();
int Lock(const char* strKey, DWORD dwConnection);
int Unlock(const char* strKey, DWORD dwConnection);
int ExclusiveLock(DWORD dwConnection);
BOOL IsLocked() const { return m_dwExclusiveLocker != 0; }
int ExclusiveUnlock(DWORD dwConnection);
TTableDef(CdbDatabase* db, LPCSTR strTableName);
virtual ~TTableDef();
};
CdbTableDef TTableDef::GetTableDef()
{
return (*m_db)[m_strTableName];
}
CdbRecordset& TTableDef::GetDynaset()
{
if (!m_Dynaset.Exists())
{
// Genera la query basata sulla chiave primaria = 0
CString strQuery;
strQuery = "SELECT * FROM ";
strQuery += m_strTableName;
strQuery = " ORDER BY ";
CdbTableDef dbTable = (*m_db)[m_strTableName];
CdbIndex dbIndex = dbTable.Indexes[0L];
CdbFields& idxFields = dbIndex.Fields;
for (int f = 0; f < idxFields.GetCount(); f++)
{
if (f) strQuery += ",";
strQuery += idxFields[f].GetName();
}
strQuery += ";";
m_Dynaset = m_db->OpenRecordset(strQuery, dbOpenDynaset);
}
return m_Dynaset;
}
int TTableDef::Lock(const char* strKey, DWORD dwConnection)
{
DWORD dwLocker;
if (!m_Locks.Lookup(strKey, dwLocker))
{
m_Locks[strKey] = dwConnection;
dwLocker = dwConnection;
}
return dwLocker == dwConnection ? NOERR : _islocked;
}
int TTableDef::Unlock(LPCSTR strKey, DWORD dwConnection)
{
int err = NOERR;
if (strKey)
{
DWORD dwLocker;
if (m_Locks.Lookup(strKey, dwLocker))
{
if (dwLocker == dwConnection)
m_Locks.RemoveKey(strKey);
else
err = _islocked;
}
}
else
{
for (POSITION pos = m_Locks.GetStartPosition(); pos; )
{
CString strKey;
DWORD dwLocker;
m_Locks.GetNextAssoc(pos, strKey, dwLocker);
if (dwLocker == dwConnection)
m_Locks.RemoveKey(strKey);
}
}
return err;
}
int TTableDef::ExclusiveLock(DWORD dwConnection)
{
if (m_dwExclusiveLocker == dwConnection)
return NOERR;
if (m_dwExclusiveLocker != 0 || m_nReferences > 1)
return _islocked;
m_dwExclusiveLocker = dwConnection;
return NOERR;
}
int TTableDef::ExclusiveUnlock(DWORD dwConnection)
{
if (m_dwExclusiveLocker == dwConnection)
m_dwExclusiveLocker = 0;
return m_dwExclusiveLocker == 0 ? NOERR : _islocked;
}
TTableDef::TTableDef(CdbDatabase* db, LPCSTR strTableName)
: m_db(db), m_strTableName(strTableName),
m_nReferences(0), m_dwExclusiveLocker(0)
{
m_tModifyTime = clock();
}
TTableDef::~TTableDef()
{
ASSERT(m_nReferences == 0);
if (m_Dynaset.Exists())
m_Dynaset.Close();
}
/////////////////////////////////////////////////////////////////////////////
// TTableDefPool
class TTableDefPool : public CObject
{
CMap<DWORD,DWORD,TTableDef*, TTableDef*> m_Tables;
protected:
enum { FIRM_MULTIPLIER = 10000 };
DWORD LogToIndex(int nFirm, int nLogicNumber) const;
public:
TTableDef* Find(int nFirm, int nLogicNumber) const;
void Add(int nFirm, int nLogicNumber, TTableDef* pTable);
void AddReference(int nFirm, int nLogicNumber);
TTableDef& TableDef(int nFirm, int nLogicNumber) const;
int RemoveReference(int nFirm, int nLogicNumber);
BOOL FindFirm(int nFirm) const;
TTableDefPool();
virtual ~TTableDefPool();
};
DWORD TTableDefPool::LogToIndex(int nFirm, int nLogicNumber) const
{
DWORD dwIndex = (nFirm * FIRM_MULTIPLIER) + nLogicNumber;
return dwIndex;
}
TTableDef* TTableDefPool::Find(int nFirm, int nLogicNumber) const
{
const DWORD dwIndex = LogToIndex(nFirm, nLogicNumber);
TTableDef* pTable;
BOOL bOk = m_Tables.Lookup(dwIndex, pTable);
return bOk ? pTable : NULL;
}
TTableDef& TTableDefPool::TableDef(int nFirm, int nLogicNumber) const
{
return *Find(nFirm, nLogicNumber);
}
void TTableDefPool::Add(int nFirm, int nLogicNumber, TTableDef* pTable)
{
ASSERT(Find(nFirm, nLogicNumber) == NULL);
const DWORD dwIndex = LogToIndex(nFirm, nLogicNumber);
m_Tables.SetAt(dwIndex, pTable);
}
void TTableDefPool::AddReference(int nFirm, int nLogicNumber)
{
TTableDef* pTable = Find(nFirm, nLogicNumber);
pTable->AddReference();
}
// @mfunc Decrementa il numero di riferimenti al file <p nLogicNumber>
// della ditta <p nFirm>. Se questo numero e' zero allora
// rimuove la definizione dalla lista
int TTableDefPool::RemoveReference(int nFirm, int nLogicNumber)
{
const DWORD dwIndex = LogToIndex(nFirm, nLogicNumber);
int nRef = 0;
TTableDef* pTable;
if (m_Tables.Lookup(dwIndex, pTable))
{
nRef = pTable->RemoveReference();
if (nRef == 0)
{
delete pTable;
m_Tables.RemoveKey(dwIndex);
}
}
return nRef;
}
// @mfunc Verifica l'esistenza di almeno un file appartenente
// alla ditta <p nFirm>
BOOL TTableDefPool::FindFirm(int nFirm) const
{
POSITION pos;
for (pos = m_Tables.GetStartPosition(); pos;)
{
DWORD dwIndex;
TTableDef* pTable;
m_Tables.GetNextAssoc(pos, dwIndex, pTable);
if (int(dwIndex / FIRM_MULTIPLIER) == nFirm)
break;
}
return pos != NULL;
}
TTableDefPool::TTableDefPool()
{
}
// @mfunc Vuota la lista delle definizioni delle tabelle SQL
TTableDefPool::~TTableDefPool()
{
for (POSITION pos = m_Tables.GetStartPosition(); pos;)
{
DWORD dwIndex;
TTableDef* pTable;
m_Tables.GetNextAssoc(pos, dwIndex, pTable);
// Azzera i riferimenti prima di distruggere
pTable->ZeroReferences();
delete pTable;
}
m_Tables.RemoveAll();
}
/////////////////////////////////////////////////////////////////////////////
// TSnapshot
class TSnapshot : public CObject
{
CdbDatabase* m_db;
CString m_strQuery;
CdbRecordset* m_Snapshot;
long m_nPosition;
BOOL m_bReusable;
clock_t m_tCreationTime;
clock_t m_tAccessTime;
public:
clock_t GetCreationTime() const { return m_tCreationTime; }
clock_t GetAccessTime() const { return m_tAccessTime; }
BOOL IsEqual(const CdbDatabase* pDatabase, LPCSTR sQuery) const;
BOOL IsOpen() const;
CdbRecordset& GetSnapshot();
void Update();
void Close();
void MakeReusable();
BOOL Reusable() const { return m_bReusable; }
void Reuse();
TSnapshot(CdbDatabase* db, LPCSTR strQuery);
virtual ~TSnapshot();
};
BOOL TSnapshot::IsOpen() const
{
return m_Snapshot != NULL;
}
CdbRecordset& TSnapshot::GetSnapshot()
{
if (!IsOpen())
{
m_tCreationTime = clock();
m_Snapshot = new CdbRecordset;
try
{
*m_Snapshot = m_db->OpenRecordset(m_strQuery, dbOpenSnapshot);
}
catch(...)
{
TRACE("Can't open snapshot!");
ASSERT(0);
}
if (m_nPosition > 0)
{
try
{
m_Snapshot->Move(m_nPosition);
}
catch(...)
{
TRACE("Can't restore snapshot position!");
}
}
}
m_tAccessTime = clock();
return *m_Snapshot;
}
void TSnapshot::Update()
{
if (IsOpen())
{
m_tCreationTime = clock();
m_Snapshot->Requery();
}
}
void TSnapshot::MakeReusable()
{
ASSERT(!m_bReusable);
m_bReusable = TRUE;
}
void TSnapshot::Reuse()
{
ASSERT(m_bReusable);
m_bReusable = FALSE;
}
void TSnapshot::Close()
{
if (IsOpen())
{
m_nPosition = m_Snapshot->GetAbsolutePosition();
m_Snapshot->Close();
delete m_Snapshot;
m_Snapshot = NULL;
m_tCreationTime = 0;
}
}
BOOL TSnapshot::IsEqual(const CdbDatabase* pDatabase,
LPCSTR sQuery) const
{
return m_db == pDatabase && m_strQuery == sQuery;
}
TSnapshot::TSnapshot(CdbDatabase* db, LPCSTR strQuery)
: m_db(db), m_Snapshot(NULL), m_strQuery(strQuery),
m_tAccessTime(0), m_tCreationTime(0), m_nPosition(-1),
m_bReusable(FALSE)
{
}
TSnapshot::~TSnapshot()
{
Close();
}
/////////////////////////////////////////////////////////////////////////////
// TSnapshotPool
class TSnapshotPool : public CObject
{
CMap<DWORD,DWORD,TSnapshot*,TSnapshot*> m_Snapshots;
DWORD m_dwNextId;
protected:
DWORD RecycleSnapshot(CdbDatabase* pDatabase, LPCSTR sQuery);
public:
DWORD AddSnapshot(CdbDatabase* pDatabase, LPCSTR sQuery);
TSnapshot& operator[](DWORD nHandle)
{ return *m_Snapshots[nHandle]; }
void RemoveSnapshot(DWORD nHandle);
TSnapshotPool();
virtual ~TSnapshotPool();
};
TSnapshotPool::TSnapshotPool()
: m_dwNextId(0)
{
}
// @mfunc Data <p sQuery> cerca uno snapshot inutilizzato che
// abbia la stessa query: se lo trova lo riutilizza
DWORD TSnapshotPool::RecycleSnapshot(CdbDatabase* pDatabase,
LPCSTR sQuery)
{
for (POSITION pos = m_Snapshots.GetStartPosition(); pos; )
{
DWORD dwId;
TSnapshot* pSnapshot;
m_Snapshots.GetNextAssoc(pos, dwId, pSnapshot);
if (pSnapshot->Reusable() &&
pSnapshot->IsEqual(pDatabase, sQuery))
{
pSnapshot->Reuse();
return dwId;
}
}
return 0;
}
DWORD TSnapshotPool::AddSnapshot(CdbDatabase* pDatabase,
LPCSTR sQuery)
{
// Tenta di riciclare uno Snapshot precedente gia' aperto
DWORD dwId = RecycleSnapshot(pDatabase, sQuery);
if (dwId)
return dwId;
TSnapshot* pNew = new TSnapshot(pDatabase, sQuery);
const int MAX_OPEN = 32;
if (m_Snapshots.GetCount() > MAX_OPEN)
{
TSnapshot* pOld = NULL;
DWORD dwOldId = 0;
int nReallyOpen = 0;
for (POSITION pos = m_Snapshots.GetStartPosition(); pos; )
{
DWORD dwId;
TSnapshot* pSnapshot;
m_Snapshots.GetNextAssoc(pos, dwId, pSnapshot);
if (pSnapshot->IsOpen())
{
nReallyOpen++;
if (pOld == NULL ||
pSnapshot->GetAccessTime() < pOld->GetAccessTime())
{
pOld = pSnapshot;
dwOldId = dwId;
}
}
}
if (nReallyOpen > MAX_OPEN);
{
pOld->Close();
if (pOld->Reusable())
RemoveSnapshot(dwOldId);
}
}
m_dwNextId++;
m_Snapshots.SetAt(m_dwNextId, pNew);
return m_dwNextId;
}
void TSnapshotPool::RemoveSnapshot(DWORD nHandle)
{
TSnapshot* pSnapshot = m_Snapshots[nHandle];
if (pSnapshot->IsOpen())
pSnapshot->MakeReusable();
else
{
delete pSnapshot;
m_Snapshots.RemoveKey(nHandle);
}
}
TSnapshotPool::~TSnapshotPool()
{
for (POSITION pos = m_Snapshots.GetStartPosition(); pos; )
{
DWORD dwId;
TSnapshot* pSnapshot;
m_Snapshots.GetNextAssoc(pos, dwId, pSnapshot);
delete pSnapshot;
}
m_Snapshots.RemoveAll();
}
///////////////////////////////////////////////////////////
// TPrassiServer
TConnection* TPrassiServer::OnCreateConnection(DWORD id)
{
Trace(0, "Connecting %lu", id);
return new TPrassiConnection(this, id);
}
BOOL TPrassiServer::OnRemoveConnection(DWORD id)
{
Trace(0, "Disconnecting %lu", id);
return BASE_SERVER::OnRemoveConnection(id);
}
BOOL TPrassiServer::TestFirm(int nFirm) const
{
BOOL bOk = m_pTables->FindFirm(nFirm);
if (!bOk)
bOk = m_pDataSources->TestDataSource("FIRM", nFirm);
return bOk;
}
BOOL TPrassiServer::OpenTableDef(int nFirm, int nLogicNumber)
{
TTableDef* pTable = m_pTables->Find(nFirm, nLogicNumber);
if (pTable == NULL)
{
CString strTableName;
CdbDatabase* db =
m_pDataSources->GetDataSource(nFirm,
nLogicNumber,
strTableName);
if (db == NULL)
return FALSE;
try
{
(*db)[strTableName].Exists();
}
catch(...)
{
m_pDataSources->ReleaseDataSource(nFirm, nLogicNumber);
return FALSE;
}
pTable = new TTableDef(db, strTableName);
m_pTables->Add(nFirm, nLogicNumber, pTable);
}
if (pTable != NULL)
{
if (pTable->IsLocked())
return FALSE;
m_pTables->AddReference(nFirm, nLogicNumber);
}
return pTable != NULL;
}
CdbTableDef TPrassiServer::GetTableDef(int nFirm, int nLogicNumber)
{
TTableDef* pTable = m_pTables->Find(nFirm, nLogicNumber);
return pTable->GetTableDef();
}
CdbRecordset& TPrassiServer::GetDynaset(int nFirm, int nLogicNumber)
{
TTableDef* pTable = m_pTables->Find(nFirm, nLogicNumber);
return pTable->GetDynaset();
}
void TPrassiServer::CloseTableDef(int nFirm, int nLogicNumber)
{
int nRef = m_pTables->RemoveReference(nFirm, nLogicNumber);
if (nRef == 0)
m_pDataSources->ReleaseDataSource(nFirm, nLogicNumber);
}
DWORD TPrassiServer::OpenSnapshot(int nFirm, int nLogicNumber,
LPCSTR sWhere, LPCSTR sOrder)
{
TTableDef* pTable = m_pTables->Find(nFirm, nLogicNumber);
CString strQuery;
if (sOrder || sWhere)
{
strQuery = "SELECT * FROM ";
strQuery += pTable->GetTableName();
if (sWhere)
{
strQuery += " WHERE ";
strQuery += sWhere;
}
if (sOrder)
{
strQuery += " ORDER BY ";
int nKey = atoi(sOrder);
if (nKey > 0)
{
CdbTableDef dbTable = pTable->GetTableDef();
CdbIndex dbIndex = dbTable.Indexes[nKey-1];
CdbFields& idxFields = dbIndex.Fields;
for (int f = 0; f < idxFields.GetCount(); f++)
{
if (f) strQuery += ",";
strQuery += idxFields[f].GetName();
}
}
else
strQuery += sOrder;
}
strQuery += ";";
}
else
strQuery = pTable->GetTableName();
CdbDatabase* pDatabase = &pTable->GetDatabase();
DWORD dwHandle = m_pSnapshots->AddSnapshot(pDatabase, strQuery);
return dwHandle;
}
CdbRecordset& TPrassiServer::GetSnapshot(DWORD nHandle)
{
return (*m_pSnapshots)[nHandle].GetSnapshot();
}
BOOL TPrassiServer::UpdateSnapshot(DWORD nHandle,
int nFirm, int nLogicNumber)
{
TSnapshot& snap = (*m_pSnapshots)[nHandle];
const clock_t tCreationTime = snap.GetCreationTime();
const TTableDef* pTable = m_pTables->Find(nFirm, nLogicNumber);
ASSERT(pTable);
BOOL bChanged = pTable->IsChangedSince(tCreationTime);
if (bChanged)
snap.Update();
return bChanged;
}
void TPrassiServer::CloseSnapshot(DWORD nHandle)
{
m_pSnapshots->RemoveSnapshot(nHandle);
}
int TPrassiServer::Lock(int nFirm, int nLogicNumber,
LPCSTR sKey, DWORD dwLocker)
{
TTableDef* pTable = m_pTables->Find(nFirm, nLogicNumber);
ASSERT(pTable);
return pTable->Lock(sKey, dwLocker);
}
int TPrassiServer::Unlock(int nFirm, int nLogicNumber,
LPCSTR sKey, DWORD dwLocker)
{
TTableDef* pTable = m_pTables->Find(nFirm, nLogicNumber);
ASSERT(pTable);
return pTable->Unlock(sKey, dwLocker);
}
int TPrassiServer::ExclusiveLock(int nFirm, int nLogicNumber, DWORD dwLocker)
{
TTableDef* pTable = m_pTables->Find(nFirm, nLogicNumber);
ASSERT(pTable);
return pTable->ExclusiveLock(dwLocker);
}
int TPrassiServer::ExclusiveUnlock(int nFirm, int nLogicNumber, DWORD dwLocker)
{
TTableDef* pTable = m_pTables->Find(nFirm, nLogicNumber);
ASSERT(pTable);
return pTable->ExclusiveUnlock(dwLocker);
}
///////////////////////////////////////////////////////////
// Dongle Management
///////////////////////////////////////////////////////////
#include "hlapi_c.h"
WORD TPrassiServer::m_DongleNumber;
WORD TPrassiServer::m_DongleModules[DONGLE_WORDS];
WORD TPrassiServer::DongleLogin()
{
unsigned char* REFKEY = (unsigned char*)"CAMPOKEY";
unsigned char* VERKEY = (unsigned char*)"<EFBFBD><EFBFBD>c<EFBFBD><";
const int status = HL_LOGIN(26952, LOCAL_DEVICE, REFKEY, VERKEY);
Trace(-1, "Hardlock login %s: %d",
status == STATUS_OK ? "OK" : "Failed", status);
m_DongleNumber = 0xFFFF;
if (status == STATUS_OK)
{
Word Val[4] = { 0, 0, 0, 0 };
for (int i = 0; i < 4; i++)
HL_READ(i, &Val[i]);
HL_CODE(Val, 1);
if (Val[0] == 0xFAE8)
m_DongleNumber = Val[1];
else
m_DongleNumber = 0;
}
Trace(-1, "Hardlock serial number is %s: %d",
(m_DongleNumber == 0xFFFF) ? "Bad" : "OK", (int)m_DongleNumber);
switch(m_DongleNumber)
{
case 0x0000:
memset(m_DongleModules, 0xFF, sizeof(m_DongleModules));
break;
case 0xFFFF:
memset(m_DongleModules, 0x00, sizeof(m_DongleModules));
break;
default:
{
int i;
for (i = 0; i < DONGLE_WORDS; i++)
{
HL_READ(48+i, &m_DongleModules[i]);
if (i % 4 == 3)
HL_CODE(&m_DongleModules[i-3], 1);
}
for (i = 0; i < DONGLE_WORDS; i++)
m_DongleModules[i] ^= m_DongleNumber;
}
break;
}
return m_DongleNumber;
}
void TPrassiServer::DongleLogout()
{
HL_LOGOUT();
m_DongleNumber = 0xFFFF;
memset(m_DongleModules, 0x00, sizeof(m_DongleModules));
}
BOOL TPrassiServer::IsOk() const
{
BOOL ok = BASE_SERVER::IsOk();
if (ok)
ok &= m_pDataSources->IsOk();
return ok;
}
TPrassiServer::TPrassiServer()
: BASE_SERVER("PRASSI")
{
m_pDataSources = new TDataSources;
m_pTables = new TTableDefPool;
m_pSnapshots = new TSnapshotPool;
}
TPrassiServer::~TPrassiServer()
{
delete m_pSnapshots;
delete m_pTables;
delete m_pDataSources;
}
///////////////////////////////////////////////////////////
// Start/Get/Stop server
static TPrassiServer* pServer = NULL;
BOOL StopServer()
{
BOOL ok = pServer != NULL;
if (ok)
{
TPrassiServer::DongleLogout();
delete pServer;
pServer = NULL;
}
return ok;
}
BOOL StartServer()
{
BOOL ok = pServer == NULL;
if (ok)
{
ok = TPrassiServer::DongleLogin() != 0xFFFF;
if (ok)
{
pServer = new TPrassiServer;
if (!pServer->IsOk())
{
StopServer();
AfxMessageBox("ODBC initialization failure.",
MB_OK | MB_ICONERROR);
}
}
else
{
AfxMessageBox("Error connecting to the dongle.",
MB_OK | MB_ICONERROR);
}
ok = pServer != NULL;
}
return ok;
}
TPrassiServer& GetServer()
{
if (pServer == NULL);
StartServer();
ASSERT(pServer);
return *pServer;
}