6a0d7b3256
Files correlati : lurch.exe authoriz.exe Ricompilazione Demo : [ ] Commento : Aggiunto comando DongleInfo che riassume in se DongleNumber+DongleYear+DongleModules in modo da ridurre il traffico di rete col server git-svn-id: svn://10.65.10.50/trunk@20132 c028cbd2-c16b-5b4b-a496-9718f37d4682
1147 lines
28 KiB
C++
Executable File
1147 lines
28 KiB
C++
Executable File
#include <wx/wx.h>
|
|
|
|
#include "baseserv.h"
|
|
|
|
#include <wx/dbtable.h>
|
|
#include <wx/dynarray.h>
|
|
#include <wx/mstream.h>
|
|
|
|
wxString GetSoapParam(const TXmlItem &xmlMethod, const char* strParam)
|
|
{
|
|
wxString val;
|
|
const TXmlItem* xml = xmlMethod.FindFirst(strParam);
|
|
if (xml != NULL)
|
|
val = xml->GetEnclosedText();
|
|
return val;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TRecord
|
|
// Tabella di database con 1 o piu' viste in base alla chiave
|
|
///////////////////////////////////////////////////////////
|
|
|
|
class TRecord : public wxObject
|
|
{
|
|
private:
|
|
wxArrayString m_Fields;
|
|
wxString m_strLocker; // User locking the record
|
|
bool m_bDeleted;
|
|
|
|
public:
|
|
bool Locked() const { return !m_strLocker.IsEmpty(); }
|
|
const wxString& LockedBy() const { return m_strLocker; }
|
|
|
|
bool Deleted() const { return m_bDeleted; }
|
|
void MarkAsDeleted() { m_bDeleted = true; }
|
|
void MarkAsUndeleted() { m_bDeleted = false; }
|
|
|
|
void Add(const wxString& strValue) { m_Fields.Add(strValue); }
|
|
|
|
const wxString& operator[] (size_t i) const { return m_Fields[i]; }
|
|
wxString& operator[] (size_t i) { return m_Fields[i]; }
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TArrayObject
|
|
///////////////////////////////////////////////////////////
|
|
|
|
WX_DEFINE_ARRAY(wxObject*, TArrayObject);
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TIndexEntry
|
|
///////////////////////////////////////////////////////////
|
|
|
|
struct TIndexEntry : public wxObject
|
|
{
|
|
wxString m_strkey;
|
|
long m_nRecno;
|
|
};
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TIndex
|
|
///////////////////////////////////////////////////////////
|
|
|
|
class TIndex : public wxObject
|
|
{
|
|
enum { MAX_KEY_ENTRIES = 8 };
|
|
int m_nField[MAX_KEY_ENTRIES];
|
|
int m_nSize[MAX_KEY_ENTRIES];
|
|
bool m_bUpper[MAX_KEY_ENTRIES];
|
|
int m_nKeyFields;
|
|
|
|
TArrayObject m_ndx;
|
|
|
|
protected:
|
|
void AddRecord(const TRecord& rec, long recno);
|
|
long FindPosition(long recno) const;
|
|
|
|
public:
|
|
void AddKeyField(int nPos, int nSize, bool upper);
|
|
long FindPosition(const wxString& key) const;
|
|
long SkipTo(long recno, long offset) const;
|
|
void Update(const TArrayObject& records);
|
|
bool Ok() const { return m_nKeyFields > 0; }
|
|
long GetCount() const { return m_ndx.GetCount(); }
|
|
|
|
TIndex();
|
|
};
|
|
|
|
void TIndex::AddKeyField(int nPos, int nSize, bool upper)
|
|
{
|
|
if (m_nKeyFields < MAX_KEY_ENTRIES)
|
|
{
|
|
m_nField[m_nKeyFields] = nPos;
|
|
m_nSize[m_nKeyFields] = nPos;
|
|
m_bUpper[m_nKeyFields] = upper;
|
|
m_nKeyFields++;
|
|
}
|
|
}
|
|
|
|
long TIndex::FindPosition(const wxString& key) const
|
|
{
|
|
int nFirst = 0;
|
|
int nLast = m_ndx.GetCount()-1;
|
|
while (nFirst <= nLast)
|
|
{
|
|
const int nCurr = (nFirst + nLast) / 2;
|
|
const int nCmp = ((TIndexEntry*)m_ndx[nCurr])->m_strkey.Cmp(key);
|
|
if (nCmp == 0)
|
|
return nCurr;
|
|
if (nCmp > 0)
|
|
nLast = nCurr-1;
|
|
if (nCmp < 0)
|
|
nFirst = nCurr+1;
|
|
}
|
|
return nFirst;
|
|
}
|
|
|
|
long TIndex::FindPosition(long recno) const
|
|
{
|
|
long i;
|
|
for (i = m_ndx.GetCount()-1; i >= 0; i--)
|
|
if (((TIndexEntry*)m_ndx[i])->m_nRecno == recno)
|
|
break;
|
|
return i;
|
|
}
|
|
|
|
long TIndex::SkipTo(long recno, long offset) const
|
|
{
|
|
const long tot = m_ndx.GetCount();
|
|
long i = 0;
|
|
if (tot > 0)
|
|
{
|
|
if (recno == 0) // Goto first
|
|
i = ((TIndexEntry*)m_ndx[0])->m_nRecno; else
|
|
if (recno < 0) // Goto last
|
|
i = ((TIndexEntry*)m_ndx[tot-1])->m_nRecno; else
|
|
{
|
|
const long p = FindPosition(recno) + offset;
|
|
if (p >= 0 && p < tot)
|
|
i = ((TIndexEntry*)m_ndx[p])->m_nRecno;
|
|
}
|
|
}
|
|
return i;
|
|
}
|
|
|
|
void TIndex::AddRecord(const TRecord& rec, long recno)
|
|
{
|
|
TIndexEntry* e = new TIndexEntry;
|
|
e->m_nRecno = recno;
|
|
for (int i = 0; i < m_nKeyFields; i++)
|
|
{
|
|
const char* val = rec[m_nField[i]];
|
|
if (m_bUpper[i])
|
|
{
|
|
e->m_strkey.Printf("%*s", -m_nSize[i], val);
|
|
e->m_strkey.Upper();
|
|
}
|
|
else
|
|
e->m_strkey.Printf("%*s", m_nSize[i], val);
|
|
}
|
|
|
|
const int nPos = FindPosition(e->m_strkey);
|
|
m_ndx.Insert(e, nPos);
|
|
}
|
|
|
|
void TIndex::Update(const TArrayObject& records)
|
|
{
|
|
WX_CLEAR_ARRAY(m_ndx);
|
|
for (size_t i = 0; i < records.GetCount(); i++)
|
|
AddRecord(*((TRecord*)records[i]), i+1);
|
|
}
|
|
|
|
TIndex::TIndex() : m_nKeyFields(0)
|
|
{ }
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TTable
|
|
// Tabella di database con 1 o piu' viste in base alla chiave
|
|
///////////////////////////////////////////////////////////
|
|
|
|
class TTable : public wxObject
|
|
{
|
|
wxDbColInf* m_ci;
|
|
wxDbTable* m_table;
|
|
UWORD m_nColumns;
|
|
char* m_field[128];
|
|
|
|
TArrayObject m_Records, m_Indexes;
|
|
long m_nCurrent;
|
|
|
|
protected:
|
|
void KillRecordSet();
|
|
bool FillRecordSet();
|
|
bool GoTo(long& recno);
|
|
|
|
int FindColumn(const char* name) const;
|
|
|
|
public:
|
|
long Rows(int index) const;
|
|
void GetRecord(long recno, wxOutputStream& out);
|
|
void GetRecordLength(wxOutputStream& out);
|
|
bool CreateIndex(int index, const TXmlItem& fields);
|
|
TIndex& Index(int n);
|
|
|
|
bool ok() const { return m_nColumns > 0; }
|
|
|
|
TTable(wxDb* db, const wxString& strName);
|
|
virtual ~TTable();
|
|
};
|
|
|
|
long TTable::Rows(int index) const
|
|
{
|
|
const TIndex& idx = ((TTable*)this)->Index(index);
|
|
return idx.Ok() ? idx.GetCount() : m_Records.GetCount();
|
|
}
|
|
|
|
bool TTable::GoTo(long& rec)
|
|
{
|
|
const long tot = m_Records.GetCount();
|
|
bool ok = false;
|
|
if (rec < 0) // -1 = last record
|
|
rec = tot + rec + 1;
|
|
if (rec > 0 && rec <= tot)
|
|
{
|
|
m_nCurrent = rec;
|
|
ok = true;
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
void TTable::GetRecord(long recno, wxOutputStream& out)
|
|
{
|
|
if (GoTo(recno))
|
|
{
|
|
const TRecord& record = *((TRecord*)m_Records[m_nCurrent-1]);
|
|
|
|
TXmlItem rec; rec.SetTag("Record");
|
|
rec.SetAttr("RecNo", recno);
|
|
for (UWORD c = 0; c < m_nColumns; c++)
|
|
{
|
|
const wxString& str = record[c];
|
|
if (!str.IsEmpty() && str != "1899-12-30")
|
|
rec.AddSoapString("Field", str).SetAttr("Name", m_ci[c].colName);
|
|
}
|
|
rec.Write(out, 2);
|
|
}
|
|
}
|
|
|
|
void TTable::GetRecordLength(wxOutputStream& out)
|
|
{
|
|
int len = 0;
|
|
for (UWORD i = 0; i < m_nColumns; i++)
|
|
{
|
|
const wxDbColInf& ci = m_ci[i];
|
|
switch (ci.sqlDataType)
|
|
{
|
|
case SQL_C_DATE:
|
|
len += 8;
|
|
break;
|
|
default:
|
|
if (ci.bufferSize > 128) // It's a MEMO!
|
|
len += 10;
|
|
else
|
|
len += ci.bufferSize;
|
|
break;
|
|
}
|
|
}
|
|
out << wxString::Format("%d", len);
|
|
}
|
|
|
|
int TTable::FindColumn(const char* name) const
|
|
{
|
|
int i = m_nColumns-1;
|
|
for ( ; i >= 0; i--)
|
|
{
|
|
if (wxStricmp(m_ci[i].colName, name) == 0)
|
|
break;
|
|
}
|
|
return i;
|
|
}
|
|
|
|
TIndex& TTable::Index(int index)
|
|
{
|
|
if (index < 0 || index > 8)
|
|
index = 0;
|
|
for (int i = m_Indexes.GetCount(); i <= index; i++)
|
|
m_Indexes.Add(new TIndex);
|
|
return *((TIndex*)m_Indexes[index]);
|
|
}
|
|
|
|
bool TTable::CreateIndex(int index, const TXmlItem& fields)
|
|
{
|
|
TIndex& ndx = Index(index);
|
|
if (!ndx.Ok())
|
|
{
|
|
for (int c = 0; c < fields.GetChildren(); c++)
|
|
{
|
|
const TXmlItem& field = *fields.GetChild(c);
|
|
if (field.GetTag() == "Field")
|
|
{
|
|
const int i = FindColumn(field.GetAttr("Name"));
|
|
if (i >= 0)
|
|
{
|
|
const bool upper = !field.GetAttr("Upper").IsEmpty();
|
|
ndx.AddKeyField(i, m_ci[i].bufferSize, upper);
|
|
}
|
|
}
|
|
}
|
|
ndx.Update(m_Records);
|
|
}
|
|
|
|
return ndx.Ok();
|
|
}
|
|
|
|
void TTable::KillRecordSet()
|
|
{
|
|
WX_CLEAR_ARRAY(m_Records);
|
|
m_Records.Clear();
|
|
}
|
|
|
|
bool TTable::FillRecordSet()
|
|
{
|
|
KillRecordSet();
|
|
const bool ok = m_table->Query();
|
|
if (ok)
|
|
{
|
|
while (m_table->GetNext())
|
|
{
|
|
TRecord* rec = new TRecord;
|
|
for (UWORD i = 0; i < m_nColumns; i++)
|
|
{
|
|
char* spc = NULL;
|
|
for (char* c = m_field[i]; *c; c++)
|
|
{
|
|
if (*c == ' ')
|
|
{
|
|
if (spc == NULL)
|
|
spc = c;
|
|
}
|
|
else
|
|
spc = NULL;
|
|
}
|
|
if (spc != NULL)
|
|
*spc = '\0';
|
|
rec->Add(m_field[i]);
|
|
}
|
|
m_Records.Add(rec);
|
|
}
|
|
}
|
|
for (size_t i = 1; i < m_Indexes.GetCount(); i++)
|
|
{
|
|
TIndex& ndx = Index(i);
|
|
if (ndx.Ok())
|
|
ndx.Update(m_Records);
|
|
}
|
|
return ok;
|
|
}
|
|
|
|
|
|
TTable::TTable(wxDb* db, const wxString& strName)
|
|
{
|
|
m_ci = db->GetColumns(strName, &m_nColumns);
|
|
|
|
m_table = new wxDbTable(db, strName, m_nColumns, strName, false);
|
|
|
|
// Bind columns
|
|
for (UWORD i = 0; i < m_nColumns; i++)
|
|
{
|
|
const wxDbColInf& ci = m_ci[i];
|
|
const int length = ci.bufferSize+1;
|
|
m_field[i] = new char[length];
|
|
memset(m_field[i], 0, length);
|
|
int nSqlType = ci.sqlDataType;
|
|
if (nSqlType <= 0 || nSqlType == 2)
|
|
nSqlType = SQL_C_CHAR;
|
|
m_table->SetColDefs(i, ci.colName, DB_DATA_TYPE_VARCHAR,
|
|
m_field[i], nSqlType, length);
|
|
}
|
|
|
|
if (m_table->Open(false, false))
|
|
{
|
|
if (!FillRecordSet())
|
|
GetServerApp().WriteLog(wxString::Format("Can't query table %s", strName.c_str()));
|
|
}
|
|
else
|
|
GetServerApp().WriteLog(wxString::Format("Can't open table %s", strName.c_str()));
|
|
|
|
m_nCurrent = 0; // Before the first
|
|
}
|
|
|
|
|
|
TTable::~TTable()
|
|
{
|
|
KillRecordSet();
|
|
|
|
delete m_table;
|
|
|
|
for (UWORD i = 0; m_field[i] != NULL; i++)
|
|
delete m_field[i];
|
|
|
|
delete m_ci;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TDataBase
|
|
// Database di dati comuni (COM) o di DITTA (00001A, ecc...)
|
|
///////////////////////////////////////////////////////////
|
|
|
|
class TDataBase : public wxHashTable
|
|
{
|
|
wxDbConnectInf m_ci;
|
|
wxDb* m_db;
|
|
|
|
public:
|
|
bool Open(const wxString& dsn, const wxString& user, const wxString& password);
|
|
bool IsOpen() const;
|
|
void Close();
|
|
wxDb& DataBase() { return *m_db; }
|
|
|
|
TTable* Table(const wxString& strName);
|
|
|
|
TDataBase();
|
|
virtual ~TDataBase();
|
|
};
|
|
|
|
bool TDataBase::Open(const wxString& dsn, const wxString& user, const wxString& password)
|
|
{
|
|
Close();
|
|
|
|
m_ci.SetDsn(dsn);
|
|
m_ci.SetUserID(user);
|
|
m_ci.SetPassword(password);
|
|
|
|
if (m_ci.AllocHenv())
|
|
{
|
|
m_db = ::wxDbGetConnection(&m_ci, false); // Forward only?
|
|
if (m_db == NULL)
|
|
m_ci.FreeHenv();
|
|
else
|
|
{
|
|
const wxString strLog = GetServerApp().GetLogFileName();
|
|
if (!strLog.IsEmpty())
|
|
m_db->SetSqlLogging(sqlLogON, strLog, TRUE);
|
|
}
|
|
}
|
|
|
|
return IsOpen();
|
|
}
|
|
|
|
void TDataBase::Close()
|
|
{
|
|
if (m_db)
|
|
{
|
|
m_db->SetSqlLogging(sqlLogOFF);
|
|
::wxDbFreeConnection(m_db);
|
|
m_db = NULL;
|
|
m_ci.FreeHenv();
|
|
}
|
|
}
|
|
|
|
bool TDataBase::IsOpen() const
|
|
{
|
|
return m_db != NULL;
|
|
}
|
|
|
|
TTable* TDataBase::Table(const wxString& strName)
|
|
{
|
|
TTable* s = (TTable*)Get(strName);
|
|
if (s == NULL)
|
|
{
|
|
s = new TTable(m_db, strName);
|
|
if (s->ok())
|
|
Put(strName, s);
|
|
}
|
|
return s;
|
|
}
|
|
|
|
TDataBase::TDataBase() : wxHashTable(wxKEY_STRING), m_db(NULL)
|
|
{
|
|
m_ci.Henv = 0;
|
|
DeleteContents(true);
|
|
}
|
|
|
|
TDataBase::~TDataBase()
|
|
{
|
|
Close();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TStudy
|
|
// Elenco di Databases: COM, 00001A, 00002A, ecc...
|
|
///////////////////////////////////////////////////////////
|
|
|
|
class TStudy : public wxHashTable
|
|
{
|
|
wxString m_strUser, m_strPass;
|
|
wxString m_strName;
|
|
|
|
public:
|
|
TDataBase& DB(long firm); // 0 = COM
|
|
TStudy(const char* strName, const char* strUser, const char* strPass);
|
|
};
|
|
|
|
TDataBase& TStudy::DB(long firm)
|
|
{
|
|
TDataBase* db = (TDataBase*)Get(firm);
|
|
if (db == NULL)
|
|
{
|
|
wxString strDsn, strPath;
|
|
|
|
if (firm > 0)
|
|
strDsn.sprintf("%s_%05lda", m_strName.c_str(), firm);
|
|
else
|
|
strDsn.sprintf("%s_COM", m_strName.c_str());
|
|
|
|
db = new TDataBase;
|
|
|
|
db->Open(strDsn, m_strUser, m_strPass);
|
|
Put(firm, db);
|
|
}
|
|
return *db;
|
|
}
|
|
|
|
TStudy::TStudy(const char* strName, const char* strUser, const char* strPass)
|
|
: wxHashTable(wxKEY_INTEGER), m_strUser(strUser), m_strPass(strPass), m_strName(strName)
|
|
{
|
|
DeleteContents(true);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TCommercialist
|
|
///////////////////////////////////////////////////////////
|
|
|
|
class TCommercialist : public wxHashTable
|
|
{
|
|
wxString m_strUser, m_strPass; // User impersonated by the TCommenrcialist
|
|
|
|
public:
|
|
const wxString& User() const { return m_strUser; }
|
|
const wxString& Password() const { return m_strPass; }
|
|
|
|
TStudy& Study(const wxString& strStudy);
|
|
TTable* Table(const TXmlItem& item);
|
|
|
|
TCommercialist();
|
|
};
|
|
|
|
TStudy& TCommercialist::Study(const wxString& strStudy)
|
|
{
|
|
TStudy* s = (TStudy*)Get(strStudy);
|
|
if (s == NULL)
|
|
{
|
|
if (m_strUser.IsEmpty())
|
|
{
|
|
TBaseServerApp& a = GetServerApp();
|
|
m_strUser = a.GetConfigString("User", "ADMIN");
|
|
m_strPass = a.GetConfigString("Password", "AD.MIN");
|
|
}
|
|
s = new TStudy(strStudy, m_strUser, m_strPass);
|
|
Put(strStudy, s);
|
|
}
|
|
return *s;
|
|
}
|
|
|
|
TTable* TCommercialist::Table(const TXmlItem& xmlMethod)
|
|
{
|
|
TTable* tab = NULL;
|
|
const wxString strStudy = GetSoapParam(xmlMethod, "Study");
|
|
const long nFirm = atol(GetSoapParam(xmlMethod, "Firm"));
|
|
TStudy& study = Study(strStudy);
|
|
TDataBase& firm = study.DB(nFirm);
|
|
if (firm.IsOpen())
|
|
{
|
|
const wxString strTable = GetSoapParam(xmlMethod, "Table");
|
|
tab = firm.Table(strTable);
|
|
}
|
|
return tab;
|
|
}
|
|
|
|
TCommercialist::TCommercialist()
|
|
{
|
|
DeleteContents(true);
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// TDataBaseServer
|
|
///////////////////////////////////////////////////////////
|
|
|
|
class TDataBaseServer : public TBaseServerApp
|
|
{
|
|
TCommercialist m_caminetti;
|
|
|
|
protected:
|
|
virtual const wxChar* GetAppName() const;
|
|
virtual bool ProcessCommand(wxString cmd, wxSocketBase& outs);
|
|
virtual bool Initialization();
|
|
virtual bool Deinitialization();
|
|
|
|
protected:
|
|
void AddAsterisk(const wxString& strField, const wxString& strQuery,
|
|
TDataBase& db, wxArrayString& arr);
|
|
wxString ParseQuery(const wxString& strOriginalQuery, TDataBase& db, wxArrayString& arr);
|
|
void WriteTable(wxString strDsn, wxString strUser,
|
|
wxString strPass, wxString strOriginalQuery,
|
|
wxOutputStream& out);
|
|
|
|
void SoapProcessMethod(const TXmlItem& xmlMethod, wxOutputStream& out);
|
|
void SoapProcessQuery(const TXmlItem &xmlMethod, wxOutputStream& out);
|
|
|
|
void SoapProcessTableRows(const TXmlItem &xmlMethod, wxOutputStream& out);
|
|
void SoapProcessGetRecord(const TXmlItem &xmlMethod, wxOutputStream& out);
|
|
void SoapProcessGetRecordLength(const TXmlItem &xmlMethod, wxOutputStream& out);
|
|
void SoapProcessCreateIndex(const TXmlItem &xmlMethod, wxOutputStream& out);
|
|
void SoapProcessSkipRecord(const TXmlItem &xmlMethod, wxOutputStream& out);
|
|
|
|
public:
|
|
bool IsMagicName(wxString& strFilename) const;
|
|
|
|
void ProcessFormQuery(const wxString& strFileName, THashTable& hashArgs);
|
|
void ProcessFormCommand(wxString cmd, wxSocketBase& outs);
|
|
void ProcessSoapCommand(wxString cmd, wxSocketBase& outs);
|
|
|
|
void GenerateIndex(wxString& strFilename);
|
|
void GenerateSql(wxString& strFilename);
|
|
void GenerateFile(wxString& strFilename);
|
|
};
|
|
|
|
// Implementare almeno queste due funzioni pure virtuali
|
|
|
|
const wxChar* TDataBaseServer::GetAppName() const
|
|
{
|
|
return "DataBase";
|
|
}
|
|
|
|
bool TDataBaseServer::IsMagicName(wxString& strFilename) const
|
|
{
|
|
wxString strName;
|
|
wxSplitPath(strFilename, NULL, &strName, NULL);
|
|
strName.MakeLower();
|
|
const int q = strName.Find('?');
|
|
if (q > 0)
|
|
strName.Truncate(q);
|
|
|
|
if (strName == "index" || strName == "sql")
|
|
{
|
|
strFilename = strName;
|
|
return true;
|
|
}
|
|
if (strName == "log")
|
|
{
|
|
strFilename = GetLogFileName();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void TDataBaseServer::GenerateIndex(wxString& strFilename)
|
|
{
|
|
TXmlItem html;
|
|
TXmlItem& body = CreatePageBody(html).AddChild("center");
|
|
|
|
TXmlItem& table = body.AddChild("table");
|
|
table.SetAttr("border", "1");
|
|
table.SetAttr("width", "70%");
|
|
|
|
TXmlItem& tr0 = body.AddChild("tr");
|
|
TXmlItem& aq = tr0.AddChild("td").AddChild("a");
|
|
aq.SetAttr("href", "sql.htm"); aq << "SQL query";
|
|
tr0.AddChild("td") << "Perform any SQL query on the selected Data Source";
|
|
|
|
TXmlItem& tr1 = body.AddChild("tr");
|
|
TXmlItem& al = tr1.AddChild("td").AddChild("a");
|
|
al.SetAttr("href", "Log"); al << "Log File";
|
|
tr1.AddChild("td") << "Display current server log";
|
|
|
|
TXmlItem& tr2 = body.AddChild("tr");
|
|
TXmlItem& as = tr2.AddChild("td").AddChild("a");
|
|
as.SetAttr("href", "stop.cgi"); as << "Stop";
|
|
tr2.AddChild("td") << "Stop this database server";
|
|
|
|
strFilename = GetTempFilename();
|
|
html.Save(strFilename);
|
|
}
|
|
|
|
void TDataBaseServer::GenerateSql(wxString& strFilename)
|
|
{
|
|
TXmlItem html;
|
|
TXmlItem& body = CreatePageBody(html).AddChild("center");
|
|
|
|
TXmlItem& form = body.AddChild("form");
|
|
form.SetAttr("method", "post");
|
|
form.SetAttr("action", "Query.cgi");
|
|
|
|
TXmlItem& table = form.AddChild("table").SetAttr("width", "70%");
|
|
|
|
TXmlItem& tr0 = table.AddChild("tr");
|
|
tr0.AddChild("td") << "Data Source Name";
|
|
TXmlItem& dsn = tr0.AddChild("td").AddChild("input");
|
|
dsn.SetAttr("type", "string"); dsn.SetAttr("name", "Dsn");
|
|
dsn.SetAttr("value", GetConfigString("Dsn"));
|
|
|
|
TXmlItem& tr1 = table.AddChild("tr");
|
|
tr1.AddChild("td") << "User";
|
|
TXmlItem& user = tr1.AddChild("td").AddChild("input");
|
|
user.SetAttr("type", "string"); user.SetAttr("name", "User");
|
|
user.SetAttr("value", GetConfigString("User"));
|
|
|
|
TXmlItem& tr2 = table.AddChild("tr");
|
|
tr2.AddChild("td") << "Password";
|
|
TXmlItem& pass = tr2.AddChild("td").AddChild("input");
|
|
pass.SetAttr("type", "password"); pass.SetAttr("name", "User");
|
|
|
|
form.AddChild("br");
|
|
form.AddChild("h3") << "SQL query:";
|
|
TXmlItem& q = form.AddChild("textarea");
|
|
q.SetAttr("name", "Sql");
|
|
q.SetAttr("cols", "80"); q.SetAttr("rows", "10");
|
|
|
|
wxString query = GetConfigString("Sql");
|
|
q << query;
|
|
|
|
form.AddChild("br");
|
|
form.AddChild("br");
|
|
|
|
TXmlItem& sub = form.AddChild("input");
|
|
sub.SetAttr("type", "submit");
|
|
sub.SetAttr("value", "Execute");
|
|
|
|
AddLinkButton(body, "Return to main page", "/");
|
|
|
|
strFilename = GetTempFilename();
|
|
html.Save(strFilename);
|
|
}
|
|
|
|
void TDataBaseServer::GenerateFile(wxString& strFilename)
|
|
{
|
|
wxString strName, strArgs;
|
|
wxSplitPath(strFilename, NULL, &strName, NULL);
|
|
strName.MakeLower();
|
|
const int q = strFilename.Find('?');
|
|
if (q > 0)
|
|
strArgs = strFilename.Mid(q+1);
|
|
|
|
if (strName == "index")
|
|
GenerateIndex(strFilename); else
|
|
if (strName == "sql")
|
|
GenerateSql(strFilename); else
|
|
if (strName == "log")
|
|
strFilename = GetLogFileName();
|
|
}
|
|
|
|
void TDataBaseServer::AddAsterisk(const wxString& strField, const wxString& strQuery,
|
|
TDataBase& db, wxArrayString& arr)
|
|
{
|
|
wxString strTable;
|
|
const int nDot = strField.Find(".*");
|
|
if (nDot < 0)
|
|
{
|
|
const int nFrom = strQuery.Find("FROM ");
|
|
if (nFrom > 0)
|
|
strTable = strQuery.Mid(nFrom+5);
|
|
const int nComma = strTable.Find(',');
|
|
const int nSpace = strTable.Find(' ');
|
|
int nTrunc = strTable.Length();
|
|
if (nComma > 0)
|
|
nTrunc = nComma;
|
|
if (nSpace > 0 && nSpace < nTrunc)
|
|
nTrunc = nSpace;
|
|
strTable.Truncate(nTrunc);
|
|
}
|
|
else
|
|
strTable = strField.Left(nDot);
|
|
strTable.Trim(false); strTable.Trim(true);
|
|
|
|
UWORD numCols;
|
|
wxDbColInf* dci = db.DataBase().GetColumns(strTable, &numCols);
|
|
|
|
wxString strFieldName;
|
|
for (UWORD i = 0; i < numCols; i++)
|
|
{
|
|
if (strField == "*")
|
|
strFieldName = dci[i].colName;
|
|
else
|
|
{
|
|
strFieldName = strTable;
|
|
strFieldName += ".";
|
|
strFieldName += dci[i].colName;
|
|
}
|
|
arr.Add(strFieldName);
|
|
}
|
|
|
|
delete dci;
|
|
}
|
|
|
|
wxString TDataBaseServer::ParseQuery(const wxString& strOriginalQuery, TDataBase& db, wxArrayString& arr)
|
|
{
|
|
wxString strQuery;
|
|
|
|
const int nSelect = strOriginalQuery.Find("SELECT ");
|
|
const int nFrom = strOriginalQuery.Find("FROM ");
|
|
|
|
if (nSelect >= 0 && nFrom > nSelect)
|
|
{
|
|
wxString strFields = strOriginalQuery.Mid(nSelect+7, nFrom-nSelect-7);
|
|
strFields.Trim(false); strFields.Trim(true);
|
|
while(!strFields.IsEmpty())
|
|
{
|
|
const int nComma = strFields.Find(',');
|
|
wxString strField = nComma < 0 ? strFields : strFields.Mid(0, nComma);
|
|
strField.Trim(); strField.Trim(false);
|
|
if (strField.Find("*") >= 0)
|
|
AddAsterisk(strField, strOriginalQuery, db, arr);
|
|
else
|
|
arr.Add(strField);
|
|
if (nComma > 0)
|
|
strFields = strFields.Mid(nComma+1);
|
|
else
|
|
break;
|
|
}
|
|
strQuery = "SELECT ";
|
|
for (size_t i = 0; i < arr.GetCount(); i++)
|
|
{
|
|
if (i > 0)
|
|
strQuery << ",";
|
|
strQuery << arr[i];
|
|
}
|
|
strQuery << strOriginalQuery.Mid(nFrom-1);
|
|
}
|
|
else
|
|
strQuery = strOriginalQuery;
|
|
|
|
return strQuery;
|
|
}
|
|
|
|
void TDataBaseServer::WriteTable(wxString strDsn, wxString strUser,
|
|
wxString strPass, wxString strOriginalQuery,
|
|
wxOutputStream& out)
|
|
{
|
|
const clock_t tTotalStart = clock();
|
|
|
|
clock_t tQueryTime = 0;
|
|
clock_t tRetrieveTime = 0;
|
|
clock_t tTotalTime = 0;
|
|
size_t nRecords = 0;
|
|
|
|
out << "<table border=1>\n";
|
|
|
|
if (strDsn.IsEmpty())
|
|
strDsn = GetConfigString("DataPath");
|
|
|
|
if (strUser.IsEmpty())
|
|
strUser = GetConfigString("User");
|
|
|
|
if (strPass.IsEmpty())
|
|
strPass = GetConfigString("Password");
|
|
|
|
TStudy s(strDsn, strUser, strPass);
|
|
TDataBase& d = s.DB(0); // Ditta/COM
|
|
if (d.IsOpen())
|
|
{
|
|
wxArrayString arr;
|
|
const wxString strQuery = ParseQuery(strOriginalQuery, d, arr);
|
|
|
|
wxDb& db = d.DataBase();
|
|
|
|
const clock_t tQueryStart = clock();
|
|
db.ExecSql(strQuery);
|
|
tQueryTime = clock() - tQueryStart;
|
|
|
|
const int nColumns = arr.GetCount();
|
|
if (nColumns > 0)
|
|
{
|
|
out << " <thead>\n";
|
|
for (int i = 0; i < nColumns; i++)
|
|
out << " <th>" << arr[i] << "</th>\n";
|
|
out << " </thead>\n";
|
|
|
|
const int bufsize = 33000;
|
|
wxChar* buffer = new wxChar[bufsize];
|
|
|
|
const clock_t tRetrieveStart = clock();
|
|
for (nRecords = 0; db.GetNext(); nRecords++)
|
|
{
|
|
out << " <tr>\n";
|
|
for (int c = 1; c <= nColumns; c++)
|
|
{
|
|
SDWORD cb;
|
|
if (db.GetData(c, SQL_C_CHAR, buffer, bufsize, &cb))
|
|
{
|
|
if (strcmp(buffer, "1899-12-30") == 0)
|
|
*buffer = '\0';
|
|
out << " <td>" << buffer << "</td>\n";
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
out << " </tr>\n";
|
|
}
|
|
delete buffer;
|
|
tRetrieveTime = clock() - tRetrieveStart;
|
|
}
|
|
}
|
|
out << "</table>\n";
|
|
|
|
tTotalTime = clock() - tTotalStart;
|
|
|
|
WriteLog(wxString::Format("--- %u Records. Query:%u Retrieve:%u Total:%u",
|
|
nRecords, (unsigned int) tQueryTime, (unsigned int) tRetrieveTime, (unsigned int) tTotalTime));
|
|
}
|
|
|
|
void TDataBaseServer::ProcessFormQuery(const wxString& strFileName, THashTable& hashArgs)
|
|
{
|
|
const wxString strDsn = hashArgs.Get("DSN");
|
|
const wxString strUser = hashArgs.Get("User");
|
|
const wxString strPass = hashArgs.Get("Password");
|
|
const wxString strOriginalQuery = hashArgs.Get("SQL");
|
|
|
|
SetConfigString("DSN", strDsn);
|
|
SetConfigString("User", strUser);
|
|
|
|
wxString strQuery = strOriginalQuery;
|
|
strQuery.Replace("\r\n", " ");
|
|
SetConfigString("SQL", strQuery);
|
|
|
|
wxFileOutputStream out(strFileName);
|
|
|
|
out << "<html>\n";
|
|
out << "<body bgcolor='#EFCEAD' background='back.gif'>\n";
|
|
|
|
WriteTable(strDsn, strUser, strPass, strOriginalQuery, out);
|
|
|
|
out << "</body>\n";
|
|
out << "</html>\n";
|
|
}
|
|
|
|
void TDataBaseServer::ProcessFormCommand(wxString cmd, wxSocketBase& outs)
|
|
{
|
|
const int stop = cmd.Find(" HTTP");
|
|
wxString strFileName = cmd.Mid(5, stop-5).Trim();
|
|
|
|
wxString strName, args;
|
|
wxSplitPath(strFileName, NULL, &strName, NULL);
|
|
|
|
const int pos = cmd.Find("\r\n\r\n");
|
|
if (pos > 0)
|
|
args = cmd.Mid(pos+4);
|
|
|
|
THashTable hashArgs(13);
|
|
ParseArguments(args, hashArgs);
|
|
|
|
strFileName = GetTempFilename();
|
|
|
|
if (strName == "Query")
|
|
ProcessFormQuery(strFileName, hashArgs);
|
|
|
|
SendFile(strFileName, outs);
|
|
}
|
|
|
|
void TDataBaseServer::SoapProcessQuery(const TXmlItem &xmlMethod, wxOutputStream& out)
|
|
{
|
|
const wxString dsn = GetSoapParam(xmlMethod, "DSN");
|
|
const wxString usr = GetSoapParam(xmlMethod, "User");
|
|
const wxString pwd = GetSoapParam(xmlMethod, "Password");
|
|
const wxString sql = GetSoapParam(xmlMethod, "SQL");
|
|
WriteTable(dsn, usr, pwd, sql, out);
|
|
}
|
|
|
|
void TDataBaseServer::SoapProcessTableRows(const TXmlItem &xmlMethod, wxOutputStream& out)
|
|
{
|
|
TTable* tab = m_caminetti.Table(xmlMethod);
|
|
if (tab != NULL)
|
|
{
|
|
const int index = atoi(GetSoapParam(xmlMethod, "Index"));
|
|
out << wxString::Format("%ld", tab->Rows(index));
|
|
}
|
|
}
|
|
|
|
void TDataBaseServer::SoapProcessGetRecord(const TXmlItem &xmlMethod, wxOutputStream& out)
|
|
{
|
|
TTable* tab = m_caminetti.Table(xmlMethod);
|
|
if (tab != NULL)
|
|
{
|
|
const long recno = atol(GetSoapParam(xmlMethod, "RecNo"));
|
|
tab->GetRecord(recno, out);
|
|
}
|
|
}
|
|
|
|
void TDataBaseServer::SoapProcessSkipRecord(const TXmlItem &xmlMethod, wxOutputStream& out)
|
|
{
|
|
TTable* tab = m_caminetti.Table(xmlMethod);
|
|
if (tab != NULL)
|
|
{
|
|
const int index = atoi(GetSoapParam(xmlMethod, "Index"));
|
|
const long recno = atol(GetSoapParam(xmlMethod, "RecNo"));
|
|
const long offset = atol(GetSoapParam(xmlMethod, "Offset"));
|
|
const long newrecno = tab->Index(index).SkipTo(recno, offset);
|
|
tab->GetRecord(newrecno, out);
|
|
}
|
|
}
|
|
|
|
|
|
void TDataBaseServer::SoapProcessGetRecordLength(const TXmlItem &xmlMethod, wxOutputStream& out)
|
|
{
|
|
TTable* tab = m_caminetti.Table(xmlMethod);
|
|
if (tab != NULL)
|
|
tab->GetRecordLength(out);
|
|
}
|
|
|
|
void TDataBaseServer::SoapProcessCreateIndex(const TXmlItem &xmlMethod, wxOutputStream& out)
|
|
{
|
|
TTable* tab = m_caminetti.Table(xmlMethod);
|
|
if (tab != NULL)
|
|
{
|
|
const int index = atoi(GetSoapParam(xmlMethod, "Index"));
|
|
const bool ok = index > 0 && tab->CreateIndex(index, xmlMethod);
|
|
out << (ok ? "1" : "0");
|
|
}
|
|
}
|
|
|
|
void TDataBaseServer::SoapProcessMethod(const TXmlItem &xmlMethod, wxOutputStream& out)
|
|
{
|
|
const wxString strTag = xmlMethod.GetTag();
|
|
wxString str = strTag;
|
|
str << "Result";
|
|
out << "<" << str << ">\n";
|
|
|
|
if (strTag == "m:GetRecord")
|
|
SoapProcessGetRecord(xmlMethod, out); else
|
|
if (strTag == "m:SkipRecord")
|
|
SoapProcessSkipRecord(xmlMethod, out); else
|
|
if (strTag == "m:GetRecordLength")
|
|
SoapProcessGetRecordLength(xmlMethod, out); else
|
|
if (strTag == "m:TableRows")
|
|
SoapProcessTableRows(xmlMethod, out); else
|
|
if (strTag == "m:CreateIndex")
|
|
SoapProcessCreateIndex(xmlMethod, out); else
|
|
if (strTag == "m:Query")
|
|
SoapProcessQuery(xmlMethod, out);
|
|
|
|
out << "</" << str << ">\n";
|
|
}
|
|
|
|
void TDataBaseServer::ProcessSoapCommand(wxString cmd, wxSocketBase& sock)
|
|
{
|
|
wxMemoryOutputStream outf;
|
|
outf << "<SOAP-ENV:Envelope>\n<SOAP-ENV:Body>\n";
|
|
|
|
const int soapstart = cmd.Find("<SOAP-ENV:");
|
|
if (soapstart > 0)
|
|
{
|
|
const size_t soaplen = cmd.length() - soapstart;
|
|
const char* buff = (const char*)cmd;
|
|
buff += soapstart;
|
|
wxMemoryInputStream input(buff, soaplen);
|
|
TXmlItem query;
|
|
if (query.Read(input))
|
|
{
|
|
const TXmlItem* pxmlBody = query.FindFirst("SOAP-ENV:Body");
|
|
if (pxmlBody != NULL) for (int m = 0; ; m++)
|
|
{
|
|
const TXmlItem* pxmlMethod = pxmlBody->GetChild(m);
|
|
if (pxmlMethod == NULL)
|
|
break;
|
|
if (pxmlMethod->GetTag().StartsWith("m:"))
|
|
{
|
|
SoapProcessMethod(*pxmlMethod, outf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
outf << "</SOAP-ENV:Body>\n</SOAP-ENV:Envelope>\n";
|
|
|
|
const size_t nSize = outf.GetSize();
|
|
char* mem = new char[nSize];
|
|
outf.CopyTo(mem, nSize);
|
|
|
|
sock << "HTTP/1.1 200 OK\n";
|
|
sock << "Server: " << GetAppName() << "\n";
|
|
sock << "Host: " << wxGetFullHostName() << "\n";
|
|
sock << "Connection: keep-alive\n";
|
|
sock << "Content-Type: text/xml; charset=utf-8\n";
|
|
sock << "Content-Length: " << nSize << "\n";
|
|
sock << "Date: " << wxDateTime::Now().Format("%#c") << "\n";
|
|
sock << "\n" << mem;
|
|
|
|
delete mem;
|
|
}
|
|
|
|
bool TDataBaseServer::ProcessCommand(wxString cmd, wxSocketBase& outs)
|
|
{
|
|
if (cmd.StartsWith("GET "))
|
|
{
|
|
const int stop = cmd.Find(" HTTP");
|
|
wxString str = cmd.Mid(4, stop-4).Trim();
|
|
if (str == "/")
|
|
str += "index.htm";
|
|
wxString strFilename = GetDocumentRoot() + str;
|
|
|
|
if (IsMagicName(strFilename))
|
|
GenerateFile(strFilename);
|
|
else
|
|
{
|
|
const int ims = cmd.Find("If-Modified-Since: ");
|
|
if (ims > 0)
|
|
{
|
|
const wxString strDate = cmd.Mid(ims+19, 24);
|
|
wxDateTime tIms;
|
|
if (tIms.ParseDateTime(strDate))
|
|
{
|
|
const wxDateTime tFile = ::wxFileModificationTime(strFilename);
|
|
if (tFile <= tIms)
|
|
{
|
|
SendNotModifiedFile(outs);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
SendFile(strFilename, outs);
|
|
return true;
|
|
}
|
|
if (cmd.StartsWith("POST "))
|
|
{
|
|
if (cmd.Find("SOAPAction") > 0)
|
|
ProcessSoapCommand(cmd, outs);
|
|
else
|
|
ProcessFormCommand(cmd, outs);
|
|
return true;
|
|
}
|
|
return TBaseServerApp::ProcessCommand(cmd, outs);
|
|
}
|
|
|
|
bool TDataBaseServer::Initialization()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
bool TDataBaseServer::Deinitialization()
|
|
{
|
|
wxDbCloseConnections();
|
|
return true;
|
|
}
|
|
|
|
// Istanziare l'applicazione principale
|
|
|
|
IMPLEMENT_APP(TDataBaseServer)
|