From 2e2223e48619d16bd39036a0d840ceb3ed195a9b Mon Sep 17 00:00:00 2001 From: randomdan Date: Fri, 11 Jun 2010 09:03:42 +0000 Subject: Use Glib::ustring in libodbcpp for data and std::string for non-data Add support for parameters in SqlViews Uses parameters to implement category browse and search --- project2/envproc.cpp | 71 ++++++++++++++++++++++++-------------------- project2/envproc.h | 4 ++- project2/p2webMain.cpp | 14 +++++++++ project2/rdbmsDataSource.cpp | 4 +-- project2/rdbmsDataSource.h | 2 +- project2/sqlView.cpp | 33 +++++++++++++++----- project2/sqlView.h | 15 +++++++++- project2/xmlObjectLoader.h | 44 +++++++++++++++++++++++++++ 8 files changed, 142 insertions(+), 45 deletions(-) create mode 100644 project2/xmlObjectLoader.h diff --git a/project2/envproc.cpp b/project2/envproc.cpp index f280aa0..e5c2a52 100644 --- a/project2/envproc.cpp +++ b/project2/envproc.cpp @@ -1,3 +1,4 @@ +#include "xmlObjectLoader.h" #include "envproc.h" #include "rdbmsDataSource.h" #include "sqlView.h" @@ -16,37 +17,9 @@ EnvironmentProcessor::init() page = elems.size() > 0 ? elems[0] : "index"; } -template -void -collectAll(std::map & objs, const xmlpp::Element * node, const Glib::ustring & name) -{ - if (!node) { - return; - } - if (name == node->get_name()) { - fprintf(stderr, "Found a %s\n", name.c_str()); - try { - objs[node->get_attribute_value("name").raw()] = Y(new X(node)); - fprintf(stderr, "Load succeeded\n"); - } - catch (const std::exception & e) { - // Assume the XML node is what we thought it was - fprintf(stderr, "Load failed (%s)\n", e.what()); - } - catch (...) { - // Assume the XML node is what we thought it was - fprintf(stderr, "Load failed\n"); - } - } - else { - BOOST_FOREACH(xmlpp::Node * child, node->get_children()) { - collectAll(objs, dynamic_cast(child), name); - } - } -} boost::shared_ptr -EnvironmentProcessor::process() +EnvironmentProcessor::process() const { fprintf(stderr, "parsing present .xml\n"); xmlpp::DomParser present("present/" + page + ".xml"); @@ -57,22 +30,39 @@ EnvironmentProcessor::process() // Collect datasources fprintf(stderr, "collecting datasources\n"); RdbmsDataSources rdbmsDataSources; - collectAll<_RdbmsDataSource>(rdbmsDataSources, presentRoot, "rdbmsdatasource"); + collectAll<_RdbmsDataSource>(rdbmsDataSources, presentRoot, "rdbmsdatasource", &_Project2SourceObject::name); // Collect views fprintf(stderr, "collecting sqlviews\n"); SqlViews sqlViews; - collectAll<_SqlView>(sqlViews, presentRoot, "sqlview"); + collectAll<_SqlView>(sqlViews, presentRoot, "sqlview", &_SqlView::name); // boost::shared_ptr responseDoc = boost::shared_ptr(new xmlpp::Document("1.0")); xmlpp::Element * responseRoot = responseDoc->create_root_node(presentRoot->get_attribute_value("root")); try { BOOST_FOREACH(SqlViews::value_type s, sqlViews) { - s.second->execute(rdbmsDataSources, responseRoot); + s.second->execute(rdbmsDataSources, responseRoot, this); } } catch (...) { } fprintf(stderr, "done views\n"); + // These were for debug... but why not pass them on? + xmlNewNs(responseRoot->cobj(), BAD_CAST "http://project2.randomdan.homeip.net/", BAD_CAST "project2"); + responseRoot->add_child("fqdn", "project2")->set_child_text(http_host); + responseRoot->add_child("requesturi", "project2")->set_child_text(request_uri); + // URL elements + xmlpp::Element * uriElems = responseRoot->add_child("uriElems", "project2"); + BOOST_FOREACH(std::string s, elems) { + uriElems->add_child("uriElem", "project2")->set_child_text(s); + } + // Parameters + xmlpp::Element * paramsXml = responseRoot->add_child("params", "project2"); + BOOST_FOREACH(RegMultiMatch::value_type u, params) { + xmlpp::Element * param = paramsXml->add_child("param", "project2"); + param->add_child_text(u[1]); + param->set_attribute("name", u[0]); + } + // XSLT Style char * buf; if (asprintf(&buf, "type=\"text/xsl\" href=\"%s\"", presentRoot->get_attribute_value("style").c_str()) > 0) { @@ -84,3 +74,20 @@ EnvironmentProcessor::process() return responseDoc; } +Glib::ustring +EnvironmentProcessor::getParamUri(const std::string & p) const +{ + return elems[atoi(p.c_str())]; +} + +Glib::ustring +EnvironmentProcessor::getParamQuery(const std::string & p) const +{ + BOOST_FOREACH(RegMultiMatch::value_type u, params) { + if (u[0] == p) { + return u[1]; + } + } + return Glib::ustring(); +} + diff --git a/project2/envproc.h b/project2/envproc.h index 8d434df..998899a 100644 --- a/project2/envproc.h +++ b/project2/envproc.h @@ -17,7 +17,9 @@ class EnvironmentProcessor { { init(); } - virtual boost::shared_ptr process(); + virtual boost::shared_ptr process() const; + Glib::ustring getParamUri(const std::string & idx) const; + Glib::ustring getParamQuery(const std::string & idx) const; private: void init(); diff --git a/project2/p2webMain.cpp b/project2/p2webMain.cpp index e8cef2c..896af0b 100644 --- a/project2/p2webMain.cpp +++ b/project2/p2webMain.cpp @@ -1,16 +1,24 @@ +// Undefine me to run from console for debugging +//#define FCGI + #include +#ifdef FCGI #include +#endif #include "envproc.h" #include +#ifdef FCGI int xmlWrite(void * _out, const char * buf, int len) { return FCGX_PutStr(buf, len, (FCGX_Stream*)_out); } +#endif int main(void) { +#ifdef FCGI FCGX_Stream *in, *_out, *err; FCGX_ParamArray envp; @@ -37,5 +45,11 @@ int main(void) FCGX_FPrintF(_out, "Unknown exception.\r\n\r\n"); } } +#else + EnvironmentProcessor ep(getenv); + + boost::shared_ptr doc = ep.process(); + xmlDocDump(stdout, doc->cobj()); +#endif return 0; } diff --git a/project2/rdbmsDataSource.cpp b/project2/rdbmsDataSource.cpp index 53a769c..10f6e75 100644 --- a/project2/rdbmsDataSource.cpp +++ b/project2/rdbmsDataSource.cpp @@ -1,10 +1,10 @@ #include "rdbmsDataSource.h" -#include "xml.h" +#include "xmlObjectLoader.h" #include _RdbmsDataSource::_RdbmsDataSource(const xmlpp::Element * p) : _Project2SourceObject(p), - masterDsn(dynamic_cast(*p->get_children("masterdsn").front()).get_child_text()->get_content()) + masterDsn(xmlChildText(p, "masterdsn")) { fprintf(stderr, "Created RDBMS Datasource %s (%s)\n", name.c_str(), masterDsn.c_str()); } diff --git a/project2/rdbmsDataSource.h b/project2/rdbmsDataSource.h index 49266e1..1fd9fac 100644 --- a/project2/rdbmsDataSource.h +++ b/project2/rdbmsDataSource.h @@ -12,7 +12,7 @@ class _RdbmsDataSource : public _Project2SourceObject { _RdbmsDataSource(const xmlpp::Element * p); ODBC::Connection & getReadonly(); ODBC::Connection & getWritable(); - const Glib::ustring masterDsn; + const std::string masterDsn; private: boost::shared_ptr database; }; diff --git a/project2/sqlView.cpp b/project2/sqlView.cpp index ad88514..7b75a81 100644 --- a/project2/sqlView.cpp +++ b/project2/sqlView.cpp @@ -4,31 +4,49 @@ #include "column.h" #include #include +#include "xmlObjectLoader.h" +#include "envproc.h" _SqlView::_SqlView(const xmlpp::Element * p) : _Project2SourceObject(p), - sql(dynamic_cast(*p->get_children("sql").front()).get_child_text()->get_content()), + sql(xmlChildText(p, "sql")), dataSource(p->get_attribute_value("datasource")), recordName(p->get_attribute_value("recordname")) { + collectAll<_Parameter>(parameters, p, "param", &_Parameter::bind); } -void _SqlView::execute(RdbmsDataSources s, xmlpp::Element * par) const +_SqlView::_Parameter::_Parameter(const xmlpp::Element * p) : + source(p->get_attribute_value("source")), + id(p->get_attribute_value("id")), + bind(atoi(p->get_attribute_value("bind").c_str())) { - typedef std::map Columns; - fprintf(stderr, "executing\n"); - ODBC::SelectCommand query(s[dataSource]->getReadonly(), sql.c_str()); +} + +void _SqlView::execute(RdbmsDataSources s, xmlpp::Element * par, const EnvironmentProcessor * ep) const +{ + typedef std::map Columns; + ODBC::SelectCommand query(s[dataSource]->getReadonly(), sql); + BOOST_FOREACH(Parameters::value_type p, parameters) { + if (p.second->source == "uri") { + query.bindParamS(p.second->bind, ep->getParamUri(p.second->id)); + } + else if (p.second->source == "query") { + query.bindParamS(p.second->bind, ep->getParamQuery(p.second->id)); + } + } xmlpp::Element * set = par->add_child(name); while (query.fetch()) { Columns columns; unsigned int cols = query.columnCount(); xmlpp::Element * record = set->add_child(recordName); for (unsigned int col = 0; col < cols; col += 1) { - const unsigned char * nameattr = query[col].name.c_str(); + const Glib::ustring & nameattr = query[col].name; char * name, * attr = NULL; - switch (sscanf((const char *)nameattr, "%a[^_]_%as", &name, &attr)) + switch (sscanf(nameattr.c_str(), "%a[^_]_%as", &name, &attr)) { case 0: + fprintf(stderr, "non-sense column name\n"); return; // Make me an exception break; case 1: @@ -76,6 +94,5 @@ void _SqlView::execute(RdbmsDataSources s, xmlpp::Element * par) const } */ } - fprintf(stderr, "finished\n"); } diff --git a/project2/sqlView.h b/project2/sqlView.h index b2e7d86..81f759b 100644 --- a/project2/sqlView.h +++ b/project2/sqlView.h @@ -7,13 +7,26 @@ #include "sourceObject.h" #include "rdbmsDataSource.h" +class EnvironmentProcessor; class _SqlView : public _Project2SourceObject { public: + class _Parameter { + public: + _Parameter(const xmlpp::Element * p); + const std::string source; + const std::string id; + const unsigned int bind; + }; + typedef boost::shared_ptr<_Parameter> Parameter; + typedef std::map Parameters; + _SqlView(const xmlpp::Element * p); - void execute(RdbmsDataSources s, xmlpp::Element *) const; + void execute(RdbmsDataSources s, xmlpp::Element *, const EnvironmentProcessor *) const; const Glib::ustring sql; const Glib::ustring dataSource; const Glib::ustring recordName; + private: + Parameters parameters; }; typedef boost::shared_ptr<_SqlView> SqlView; typedef std::map SqlViews; diff --git a/project2/xmlObjectLoader.h b/project2/xmlObjectLoader.h new file mode 100644 index 0000000..ecc97fa --- /dev/null +++ b/project2/xmlObjectLoader.h @@ -0,0 +1,44 @@ +#ifndef XMLOBJECTLOADER_H +#define XMLOBJECTLOADER_H + +#include +#include +#include +#include +#include +#include + +#define xmlChildText(p, t) dynamic_cast(*p->get_children(t).front()).get_child_text()->get_content() +template +void +collectAll(std::map & objs, const xmlpp::Element * node, const Glib::ustring & name, + const IDType ObjectBase::*id) +{ + if (!node) { + return; + } + if (name == node->get_name()) { + fprintf(stderr, "Found a %s\n", name.c_str()); + try { + ContainerType c = ContainerType(new ObjectType(node)); + objs[(*c).*id] = c; + fprintf(stderr, "Load succeeded\n"); + } + catch (const std::exception & e) { + // Assume the XML node is what we thought it was + fprintf(stderr, "Load failed (%s)\n", e.what()); + } + catch (...) { + // Assume the XML node is what we thought it was + fprintf(stderr, "Load failed\n"); + } + } + else { + BOOST_FOREACH(xmlpp::Node * child, node->get_children()) { + collectAll(objs, dynamic_cast(child), name, id); + } + } +} + +#endif + -- cgit v1.2.3