#ifndef BZS_DB_PROTOCOL_TDAP_CLIENT_TRDORMAPI_H #define BZS_DB_PROTOCOL_TDAP_CLIENT_TRDORMAPI_H /*================================================================= Copyright (C) 2013 BizStation Corp All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. =================================================================*/ #include "trdboostapi.h" #include "fieldNameAlias.h" #include "memRecord.h" #include "groupComp.h" #include #include #include namespace bzs { namespace db { namespace protocol { namespace tdap { namespace client { /** @cond INTERNAL */ template typename Container::key_type resolvKeyValue(Container& m, const std::_tstring& name, bool noexception = false); template typename Container::iterator begin(Container& m); template typename Container::iterator end(Container& m); template void clear(Container& m); template void push_back(Container& m, typename Container::row_type c); template void setValue(ROW_TYPE& row, KEY_TYPE key, const T& value); /** @endcond */ /** @cond INTERNAL */ template inline typename std::vector::iterator begin(std::vector& m) { return m.begin(); } template inline typename std::vector::iterator end(std::vector& m) { return m.end(); } template inline void push_back(std::vector& m, T c) { return m.push_back(c); } #if (_MSC_VER || (__BCPLUSPLUS__ && !defined(__clang__))) /* Container has readBefore(table_ptr, alias) function*/ template inline void readBefore(Container& mdls, table_ptr tb, const aliasMap_type* alias, typename Container::header_type* dummy = 0) { mdls.readBefore(tb, alias); } /* Container has'nt readBefore(table_ptr, alias) function*/ template inline void readBefore(...){}; #else template void push_back(Container& m, typename Container::item_type c); template class has_header { typedef char yes; typedef struct { char foo[2]; } no; template static yes test(typename C::header_type*); template static no test(...); public: #ifdef SWIG static const bool value; #else static const bool value = sizeof(test(0)) == sizeof(char); #endif }; /* Container has readBefore(table_ptr, alias) function*/ template inline void readBefore(Container& mdls, table_ptr tb, const aliasMap_type* alias, typename boost::enable_if >::type* = 0) { mdls.readBefore(tb, alias); } /* Container has'nt readBefore(table_ptr, alias) function*/ template inline void readBefore(Container& mdls, table_ptr tb, const aliasMap_type* alias, typename boost::disable_if >::type* = 0) { } #endif /* Container operation handlter */ template class mdlsHandler { mdlsHandler(); protected: Container& m_mdls; int m_option; FDI* m_fdi; MAP* m_map; template void addContainer(T* u, typename mdls_type::item_type* p) { typename mdls_type::item_type ptr(u); push_back(m_mdls, ptr); } template void addContainer(T* u, ...) { push_back(m_mdls, boost::shared_ptr(u)); } public: mdlsHandler(Container& mdls) : m_mdls(mdls) {} virtual ~mdlsHandler(){}; void init(int option, FDI* fdi, MAP& map, table_ptr tb, const aliasMap_type* alias = NULL) { m_option = option; m_fdi = fdi; m_map = ↦ readBefore(m_mdls, tb, alias); } void operator()(const fields& fds) { T* u(create(m_mdls, m_option)); m_map->readMap(*u, fds, m_option); addContainer(u, 0); } }; /* For sort in readEach */ template class compFunc { MAP& m_map; int m_keynum; public: compFunc(MAP& map, int keynum) : m_map(map), m_keynum(keynum) {} bool operator()(T* l, T* r) const { return m_map.compKeyValue(*l, *r, m_keynum); } bool operator()(boost::shared_ptr& l, boost::shared_ptr& r) const { return m_map.compKeyValue(*l, *r, m_keynum); } }; template bool sortFuncBase(const T& l, const T& r, RET (T::*func1)() const) { RET retl = (l.*func1)(); RET retr = (r.*func1)(); return retl < retr; } template bool sortFunc(const T& l, const T& r, FUNC1 func1, FUNC2 func2, FUNC3 func3) { bool v = sortFuncBase(l, r, func1); if (func2) { if (v) return v; v = sortFuncBase(r, l, func1); if (v) return !v; v = sortFuncBase(l, r, func2); if (func3) { if (v) return v; v = sortFuncBase(r, l, func2); if (v) return !v; v = sortFuncBase(l, r, func3); } } return v; } template class sortFunctor { FUNC1 m_func1; FUNC2 m_func2; FUNC3 m_func3; public: sortFunctor(FUNC1 func1, FUNC2 func2, FUNC3 func3) : m_func1(func1), m_func2(func2), m_func3(func3) { } template bool operator()(const T* l, const T* r) const { return sortFunc(*l, *r, m_func1, m_func2, m_func2); } template bool operator()(const boost::shared_ptr& l, const boost::shared_ptr& r) const { bool v = sortFunc(*l, *r, m_func1, m_func2, m_func2); return v; } }; template void sort(Container& mdls, FUNC1 func1, FUNC2 func2, FUNC3 func3) { sortFunctor functor(func1, func2, func3); std::sort(begin(mdls), end(mdls), functor); } template void sort(Container& mdls, FUNC1 func1, FUNC2 func2) { sortFunctor functor(func1, func2, NULL); std::sort(begin(mdls), end(mdls), functor); } template void sort(Container& mdls, FUNC1 func1) { sortFunctor functor(func1, NULL, NULL); std::sort(begin(mdls), end(mdls), functor); } template inline boost::shared_ptr > listup(Container& mdls, T (T2::*func)() const) { typename Container::iterator it = begin(mdls), ite = end(mdls); boost::shared_ptr > mdlst(new std::vector()); while (it != ite) { T2& mdl = *(*it); T ref = (mdl.*func)(); mdlst->push_back(ref); ++it; } return mdlst; } class mraResetter { table_ptr& m_tb; public: mraResetter(table_ptr& tb) : m_tb(tb) {} ~mraResetter() { if (m_tb->mra()) m_tb->mra()->setJoinType(mra_nojoin); m_tb->setMra(NULL); } }; /** @endcond */ template class activeObject : boost::noncopyable { void init(idatabaseManager* mgr, const _TCHAR* name) { m_tb = mgr->table(name); } void init(database_ptr& db, const _TCHAR* name, short mode) { m_tb = openTable(db, name, mode); } void init(database* db, const _TCHAR* name, short mode) { m_tb = openTable(db, name, mode); } /*void init(idatabaseManager* mgr, short tableindex) { m_tb = mgr->table(tableindex); }*/ void init(database_ptr& db, short tableindex, short mode) { m_tb = openTable(db, tableindex, mode); } void init(database* db, short tableindex, short mode) { m_tb = openTable(db, tableindex, mode); } void prepare(const pq_handle& q) { m_tb->setPrepare(q); } protected: table_ptr m_tb; FDI* m_fdi; MAP m_map; int m_option; fdNmaeAlias m_alias; public: typedef std::vector > collection_vec_type; explicit activeObject(idatabaseManager* mgr) : m_fdi(createFdi((FDI*)0)), m_map(*m_fdi), m_option(0) { init(mgr, m_map.getTableName()); if (m_tb.get() && m_fdi) initFdi(m_fdi, m_tb.get()); } explicit activeObject(database_ptr& db, short mode = TD_OPEN_NORMAL) : m_fdi(createFdi((FDI*)0)), m_map(*m_fdi), m_option(0) { init(db, m_map.getTableName(), mode); if (m_tb.get() && m_fdi) initFdi(m_fdi, m_tb.get()); } explicit activeObject(idatabaseManager* mgr, const _TCHAR* tableName) : m_fdi(createFdi((FDI*)0)), m_map(*m_fdi), m_option(0) { init(mgr, tableName); if (m_tb.get() && m_fdi) initFdi(m_fdi, m_tb.get()); } /*explicit activeObject(idatabaseManager* mgr, short tableIndex) : m_fdi(createFdi((FDI*)0)), m_map(*m_fdi), m_option(0) { init(mgr, tableIndex); if (table() && m_fdi) initFdi(m_fdi, m_tb.get()); }*/ explicit activeObject(database_ptr& db, const _TCHAR* tableName, short mode = TD_OPEN_NORMAL) : m_fdi(createFdi((FDI*)0)), m_map(*m_fdi), m_option(0) { init(db, tableName, mode); if (m_tb.get() && m_fdi) initFdi(m_fdi, m_tb.get()); } explicit activeObject(database* db, const _TCHAR* tableName, short mode = TD_OPEN_NORMAL) : m_fdi(createFdi((FDI*)0)), m_map(*m_fdi), m_option(0) { init(db, tableName, mode); if (m_tb.get() && m_fdi) initFdi(m_fdi, m_tb.get()); } explicit activeObject(database_ptr& db, short tableIndex, short mode = TD_OPEN_NORMAL) : m_fdi(createFdi((FDI*)0)), m_map(*m_fdi), m_option(0) { init(db, tableIndex, mode); if (m_tb.get() && m_fdi) initFdi(m_fdi, m_tb.get()); } explicit activeObject(database* db, short tableIndex, short mode = TD_OPEN_NORMAL) : m_fdi(createFdi((FDI*)0)), m_map(*m_fdi), m_option(0) { init(db, tableIndex, mode); if (m_tb.get() && m_fdi) initFdi(m_fdi, m_tb.get()); } ~activeObject() { destroyFdi(m_fdi); } activeObject& index(int v) { m_tb->clearBuffer(); m_tb->setKeyNum(v); return *this; } /** @cond INTERNAL */ template activeObject& keyValue(const T0 kv0) { keyValueSetter::set(m_tb, m_tb->keyNum(), kv0); return *this; } template activeObject& keyValue(const T0 kv0, const T1 kv1) { keyValueSetter::set(m_tb, m_tb->keyNum(), kv0, kv1); return *this; } template activeObject& keyValue(const T0 kv0, const T1 kv1, const T2 kv2) { keyValueSetter::set(m_tb, m_tb->keyNum(), kv0, kv1, kv2); return *this; } template activeObject& keyValue(const T0 kv0, const T1 kv1, const T2 kv2, const T3 kv3) { keyValueSetter::set(m_tb, m_tb->keyNum(), kv0, kv1, kv2, kv3); return *this; } template activeObject& keyValue(const T0 kv0, const T1 kv1, const T2 kv2, const T3 kv3, const T4 kv4) { keyValueSetter::set(m_tb, m_tb->keyNum(), kv0, kv1, kv2, kv3, kv4); return *this; } template activeObject& keyValue(const T0 kv0, const T1 kv1, const T2 kv2, const T3 kv3, const T4 kv4, const T5 kv5) { keyValueSetter::set(m_tb, m_tb->keyNum(), kv0, kv1, kv2, kv3, kv4, kv5); return *this; } template activeObject& keyValue(const T0 kv0, const T1 kv1, const T2 kv2, const T3 kv3, const T4 kv4, const T5 kv5, const T6 kv6) { keyValueSetter::set( m_tb, m_tb->keyNum(), kv0, kv1, kv2, kv3, kv4, kv5, kv6); return *this; } /** @endcond */ template activeObject& keyValue(const T0 kv0, const T1 kv1, const T2 kv2, const T3 kv3, const T4 kv4, const T5 kv5, const T6 kv6, const T7 kv7) { keyValueSetter::set( m_tb, m_tb->keyNum(), kv0, kv1, kv2, kv3, kv4, kv5, kv6, kv7); return *this; } inline table_ptr table() const { return m_tb; }; activeObject& option(int v) { m_option = v; return *this; } table::eFindType direction(const pq_handle& q) { return q->direction(); } table::eFindType direction(const queryBase& q) { return q.getDirection(); } template activeObject& readMapMore(Any_Map_type& map) { mraResetter mras(m_tb); map.init(m_option, m_fdi, m_map, m_tb, &m_alias); m_tb->find(table::findContinue); if (m_tb->lastFindDirection() == table::findForword) { findIterator itsf(*m_tb); for_each(itsf, map); } else { findRvIterator itsf(*m_tb); for_each(itsf, map); } return *this; } template activeObject& readMap(Any_Map_type& map, Query& q) { mraResetter mras(m_tb); prepare(q); if (m_tb->stat()) nstable::throwError(_T("Query is inaccurate"), &(*m_tb)); map.init(m_option, m_fdi, m_map, m_tb, &m_alias); table::eFindType direc = direction(q); m_tb->find(direc); if (direc == table::findForword) { findIterator itsf(*m_tb); for_each(itsf, map); } else { findRvIterator itsf(*m_tb); for_each(itsf, map); } return *this; } template activeObject& readMap(Any_Map_type& map, Query& q, validationFunc func) { mraResetter mras(m_tb); prepare(q); if (m_tb->stat()) nstable::throwError(_T("Query is inaccurate"), &(*m_tb)); map.init(m_option, m_fdi, m_map, m_tb, &m_alias); table::eFindType direc = direction(q); m_tb->find(direc); if (direc == table::findForword) { findIterator itsf(*m_tb); filterdFindIterator it(itsf, func); for_each(it, map); } else { findRvIterator itsf(*m_tb); filterdFindRvIterator it(itsf, func); for_each(it, map); } return *this; } template activeObject& read(collection_vec_type& mdls, Query& q, validationFunc func) { mdlsHandler map(mdls); return readMap(map, q, func); } activeObject& readMore(collection_vec_type& mdls) { mdlsHandler map(mdls); return readMapMore(map); } template activeObject& readMore(Container& mdls) { typename MAP::collection_orm_typename map(mdls); return readMapMore(map); } template activeObject& read(collection_vec_type& mdls, Query& q) { mdlsHandler map(mdls); return readMap(map, q); } template activeObject& read(Container& mdls, Query& q) { typename MAP::collection_orm_typename map(mdls); return readMap(map, q); } template activeObject& read(Container& mdls, Query& q, validationFunc func) { typename MAP::collection_orm_typename map(mdls); return readMap(map, q, func); } template void read(T2& mdl, bool setKeyValueFromObj = true) { fields fds(m_tb); if (setKeyValueFromObj) m_map.setKeyValues(mdl, fds, m_tb->keyNum()); indexIterator it = readIndex(m_tb, eSeekEqual); if (m_tb->stat() != 0) nstable::throwError(_T("activeObject read"), &(*m_tb)); m_map.readMap(mdl, fds, m_option); } template void update(T2& mdl, bool setKeyValueFromObj = true) { fields fds(m_tb); if (setKeyValueFromObj) m_map.setKeyValues(mdl, fds, m_tb->keyNum()); indexIterator it = readIndex(m_tb, eSeekEqual); if (m_tb->stat() != 0) nstable::throwError(_T("activeObject update"), &(*m_tb)); m_map.writeMap(mdl, fds, m_option); updateRecord(it); } // No need object void del() { readIndex(m_tb, eSeekEqual); if (m_tb->stat() != 0) nstable::throwError(_T("activeObject delete"), &(*m_tb)); m_tb->del(); if (m_tb->stat() != 0) nstable::throwError(_T("activeObject delete"), &(*m_tb)); } // Recieve delete record by mdl template void del(T2& mdl, bool setKeyValueFromObj = true) { read(mdl, setKeyValueFromObj); m_tb->del(); if (m_tb->stat() != 0) nstable::throwError(_T("activeObject delete"), &(*m_tb)); } template void insert(T2& mdl) { fields fds(m_tb); m_map.writeMap(mdl, fds, m_option); insertRecord(fds); m_map.readAuntoincValue(mdl, fds, m_option); } template void save(T2& mdl, bool setKeyValueFromObj = true) { fields fds(m_tb); if (setKeyValueFromObj) m_map.setKeyValues(mdl, fds, m_tb->keyNum()); indexIterator it = readIndex(m_tb, eSeekEqual); if (m_tb->stat() == STATUS_NOT_FOUND_TI) insert(mdl); else { m_map.writeMap(mdl, fds, m_option); updateRecord(it); } } #ifdef USE_CONTAINER_CUD // default not support template void update(Container& mdls) { typename Container::iterator it = begin(mdls), ite = end(mdls); while (it != ite) update(*it); } template void del(Container& mdls) { typename Container::iterator it = begin(mdls), ite = end(mdls); while (it != ite) del(*it); } template void insert(Container& mdls) { typename Container::iterator it = begin(mdls), ite = end(mdls); while (it != ite) insert(*it); } #endif /* one-to-one relation only */ template void readEach(Container& mdls, queryBase& q, bool sorted = false, bzs::rtl::exception * e = NULL) { mraResetter mras(m_tb); m_alias.reverseAliasNamesQuery(q); fields fds(m_tb); typename Container::iterator it = begin(mdls), itb = begin(mdls), ite = end(mdls); it = itb = begin(mdls); T& mdlb = *(*it); if (!m_tb->isUseTransactd()) nstable::throwError(_T("activeObject P.SQL can not use this"), (short_td)0); while (it != ite) { // if mdl has same key value, to be once read access to server T& mdl = *(*it); if ((it == itb) || !sorted || (m_map.compKeyValue(mdl, mdlb, m_tb->keyNum()) == true) || (m_map.compKeyValue(mdlb, mdl, m_tb->keyNum()) == true)) { m_map.setKeyValues(mdl, fds, m_tb->keyNum()); keydef* kd = &m_tb->tableDef()->keyDefs[(int)m_tb->keyNum()]; for (int i = 0; i < kd->segmentCount; ++i) q.addSeekKeyValue(fds[kd->segments[i].fieldNum].c_str()); } mdlb = mdl; ++it; } m_tb->setQuery(&q); if (m_tb->stat() != 0) nstable::throwError(_T("activeObject readEach Query"), &(*m_tb)); m_tb->find(); it = itb = begin(mdls); while (it != ite) { if ((m_tb->stat() != STATUS_SUCCESS) && (m_tb->stat() != STATUS_NOT_FOUND_TI)) nstable::throwError(_T("activeObject readEach"), &(*m_tb)); T& mdl = *(*it); if ((it != itb) && (!sorted || (m_map.compKeyValue(mdl, mdlb, m_tb->keyNum()) == true) || (m_map.compKeyValue(mdlb, mdl, m_tb->keyNum()) == true))) { m_tb->findNext(); if ((m_tb->stat() != STATUS_SUCCESS) && (m_tb->stat() != STATUS_NOT_FOUND_TI)) { _TCHAR buf[8192]; m_tb->keyValueDescription(buf, 8192); if (e) *e << bzs::rtl::errnoCode(m_tb->stat()) << bzs::rtl::errMessage(buf); else THROW_BZS_ERROR_WITH_CODEMSG(m_tb->stat(), buf); } } if (m_tb->stat() == 0) m_map.readMap(mdl, fds, m_option); mdlb = mdl; ++it; } } /* one-to-one relation only */ template void readEach(BaseContainer& mdls, T* (T2::*func)() const, queryBase& q) { boost::shared_ptr > refList(listup(mdls, func)); compFunc comp(m_map, m_tb->keyNum()); std::sort(refList->begin(), refList->end(), comp); readEach(*refList, q, true, NULL); } /* one-to-one relation only */ template void readEach(BaseContainer& mdls, T* (T2::*func)() const, queryBase& q, bzs::rtl::exception& e) { boost::shared_ptr > refList(listup(mdls, func)); compFunc comp(m_map, m_tb->keyNum()); std::sort(refList->begin(), refList->end(), comp); readEach(*refList, q, true, &e); } /* No use field select. one-to-one relation only */ template void readEach(Container& mdls, bool sorted = false, bzs::rtl::exception * e = NULL) { fields fds(m_tb); mraResetter mras(m_tb); typename Container::iterator it = begin(mdls), itb = begin(mdls), ite = end(mdls); it = itb = begin(mdls); T& mdlb = *(*it); while (it != ite) { T& mdl = *(*it); if ((it == itb) || !sorted || (m_map.compKeyValue(mdl, mdlb, m_tb->keyNum()) == true) || (m_map.compKeyValue(mdlb, mdl, m_tb->keyNum()) == true)) { m_map.setKeyValues(mdl, fds, m_tb->keyNum()); readIndex(m_tb, eSeekEqual); if ((m_tb->stat() != STATUS_SUCCESS) && (m_tb->stat() != STATUS_NOT_FOUND_TI)) { _TCHAR buf[8192]; m_tb->keyValueDescription(buf, 8192); if (e) *e << bzs::rtl::errnoCode(m_tb->stat()) << bzs::rtl::errMessage(buf); else THROW_BZS_ERROR_WITH_CODEMSG(m_tb->stat(), buf); } } if (m_tb->stat() == 0) m_map.readMap(mdl, fds, m_option); mdlb = mdl; ++it; } } /* No use field select. one-to-one relation only */ template void readEach(BaseContainer& mdls, T* (T2::*func)() const) { boost::shared_ptr > refList(listup(mdls, func)); compFunc comp(m_map, m_tb->keyNum()); std::sort(refList->begin(), refList->end(), comp); readEach(*refList, true, NULL); } /* one-to-one relation only */ template void readEach(BaseContainer& mdls, T* (T2::*func)() const, bzs::rtl::exception& e) { boost::shared_ptr > refList(listup(mdls, func)); compFunc comp(m_map, m_tb->keyNum()); std::sort(refList->begin(), refList->end(), comp); readEach(*refList, true, &e); } inline activeObject& alias(const _TCHAR* src, const _TCHAR* dst) { m_alias.set(src, dst); return *this; } inline activeObject& resetAlias() { m_alias.clear(); return *this; } pq_handle prepare(queryBase& q, bool serverPrepare=false) { m_alias.reverseAliasNamesQuery(q); return m_tb->prepare(&q, serverPrepare); } }; } // namespace client } // namespace tdap } // namespace protocol } // namespace db } // namespace bzs #endif // BZS_DB_PROTOCOL_TDAP_CLIENT_TRDORMAPI_H