campo-sirio/server/dbserver.cpp

622 lines
15 KiB
C++
Raw Normal View History

#include <wx/wxprec.h>
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif //WX_PRECOMP
#include "BaseServ.h"
#include <wx/dbtable.h>
//#include <wx/db.h>
#include <wx/mstream.h>
///////////////////////////////////////////////////////////
// TDataBase
///////////////////////////////////////////////////////////
class TDataBase : public wxHashTable
{
wxDbConnectInf m_ci;
wxDb* m_db;
public:
bool Open(const wxString& dsn, const wxString& user,
const wxString& password, const wxString& path);
bool IsOpen() const;
void Close();
wxDb& DataBase() { return *m_db; }
TDataBase();
virtual ~TDataBase();
};
bool TDataBase::Open(const wxString& dsn, const wxString& user,
const wxString& password, const wxString& path)
{
Close();
m_ci.SetDsn(dsn);
m_ci.SetUserID(user);
m_ci.SetPassword(password);
m_ci.SetDefaultDir(path);
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;
}
TDataBase::TDataBase() : wxHashTable(wxKEY_STRING), m_db(NULL)
{
m_ci.Henv = 0;
DeleteContents(true);
}
TDataBase::~TDataBase()
{
Close();
}
///////////////////////////////////////////////////////////
// TStudy
///////////////////////////////////////////////////////////
class TStudy : public wxHashTable
{
wxString m_strName, m_strUser, m_strPass, m_strPath;
public:
TDataBase& DB(long firm); // 0 = COM
TStudy(const char* strName, const char* strUser, const char* strPass, const char* strPath);
};
TDataBase& TStudy::DB(long firm)
{
TDataBase* db = (TDataBase*)Get(firm);
if (db == NULL)
{
wxString strDsn, strPath;
if (firm > 0)
{
strDsn.sprintf("%s%ld", m_strName, firm);
strPath.sprintf("%s/%05lda", m_strPath, firm);
}
else
{
strDsn = m_strName;
strPath.sprintf("%s/com", m_strPath);
}
db = new TDataBase;
db->Open(strDsn, m_strUser, m_strPass, strPath);
Put(firm, db);
}
return *db;
}
TStudy::TStudy(const char* strName, const char* strUser, const char* strPass, const char* strBasePath)
: wxHashTable(wxKEY_INTEGER), m_strName(strName), m_strUser(strUser), m_strPass(strPass)
{
m_strPath.sprintf("%s/%s", strBasePath, strName);
DeleteContents(true);
}
///////////////////////////////////////////////////////////
// TDataBaseServer
///////////////////////////////////////////////////////////
class TDataBaseServer : public TBaseServerApp
{
protected:
virtual const wxChar* GetAppName() const;
virtual void 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(const wxString& strDsn, const wxString& strUser,
const wxString& strPass, const wxString& strOriginalQuery,
wxFileOutputStream& out);
wxString GetSoapParam(const TXmlItem& xmlMethod, const char* strParam);
void SoapProcessQuery(const TXmlItem &xmlMethod, wxFileOutputStream& out);
void SoapProcessMethod(const TXmlItem& xmlMethod, wxFileOutputStream& 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", "Query");
q.SetAttr("cols", "80"); q.SetAttr("rows", "10");
wxString query = GetConfigString("Query");
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);
}
}
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(const wxString& strDsn, const wxString& strUser,
const wxString& strPass, const wxString& strOriginalQuery,
wxFileOutputStream& 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";
const wxString strBasePath = GetConfigString("DataPath");
TStudy s(strDsn, strUser, strPass, strBasePath);
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, tQueryTime, tRetrieveTime, 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("Query");
SetConfigString("Dsn", strDsn);
SetConfigString("User", strUser);
wxString strQuery = strOriginalQuery;
strQuery.Replace("\r\n", " ");
SetConfigString("Query", 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);
}
wxString TDataBaseServer::GetSoapParam(const TXmlItem &xmlMethod, const char* strParam)
{
wxString val;
const TXmlItem* xml = xmlMethod.FindFirst(strParam);
if (xml != NULL)
val = xml->GetEnclosedText();
return val;
}
void TDataBaseServer::SoapProcessQuery(const TXmlItem &xmlMethod, wxFileOutputStream& 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::SoapProcessMethod(const TXmlItem &xmlMethod, wxFileOutputStream& out)
{
wxString str = xmlMethod.GetTag();
str << "Result";
out << "<" << str << ">\n";
if (xmlMethod.GetTag() == "m:query")
SoapProcessQuery(xmlMethod, out);
out << "</" << str << ">\n";
}
void TDataBaseServer::ProcessSoapCommand(wxString cmd, wxSocketBase& sock)
{
const wxString strFilename = GetTempFilename();
if (!strFilename.IsEmpty())
{
wxFileOutputStream outf(strFilename);
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";
}
wxFileInputStream inf(strFilename);
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: " << inf.GetSize() << "\n";
sock << "Date: " << wxDateTime::Now().Format("%#c") << "\n";
sock << "\n";
SendContent(inf, sock);
}
void 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);
} else
if (cmd.StartsWith("POST "))
{
if (cmd.Find("SOAPAction") > 0)
ProcessSoapCommand(cmd, outs);
else
ProcessFormCommand(cmd, outs);
}
}
bool TDataBaseServer::Initialization()
{
return true;
}
bool TDataBaseServer::Deinitialization()
{
wxDbCloseConnections();
return true;
}
// Istanziare l'applicazione principale
IMPLEMENT_APP(TDataBaseServer)