comparison Framework/Plugins/IndexBackend.cpp @ 70:e6c13ddd26d9 db-changes

all integration tests passing with LookupResources extension
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 03 Jan 2019 14:04:46 +0100
parents 19764fc60ade
children a4e440e65c68
comparison
equal deleted inserted replaced
69:19764fc60ade 70:e6c13ddd26d9
54 54
55 return s; 55 return s;
56 } 56 }
57 57
58 58
59 int64_t IndexBackend::ReadInteger64(const DatabaseManager::CachedStatement& statement, 59 int64_t IndexBackend::ReadInteger64(const DatabaseManager::StatementBase& statement,
60 size_t field) 60 size_t field)
61 { 61 {
62 if (statement.IsDone()) 62 if (statement.IsDone())
63 { 63 {
64 throw Orthanc::OrthancException(Orthanc::ErrorCode_Database); 64 throw Orthanc::OrthancException(Orthanc::ErrorCode_Database);
76 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); 76 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
77 } 77 }
78 } 78 }
79 79
80 80
81 int32_t IndexBackend::ReadInteger32(const DatabaseManager::CachedStatement& statement, 81 int32_t IndexBackend::ReadInteger32(const DatabaseManager::StatementBase& statement,
82 size_t field) 82 size_t field)
83 { 83 {
84 if (statement.IsDone()) 84 if (statement.IsDone())
85 { 85 {
86 throw Orthanc::OrthancException(Orthanc::ErrorCode_Database); 86 throw Orthanc::OrthancException(Orthanc::ErrorCode_Database);
98 return static_cast<int32_t>(value); 98 return static_cast<int32_t>(value);
99 } 99 }
100 } 100 }
101 101
102 102
103 std::string IndexBackend::ReadString(const DatabaseManager::CachedStatement& statement, 103 std::string IndexBackend::ReadString(const DatabaseManager::StatementBase& statement,
104 size_t field) 104 size_t field)
105 { 105 {
106 const IValue& value = statement.GetResultField(field); 106 const IValue& value = statement.GetResultField(field);
107 107
108 switch (value.GetType()) 108 switch (value.GetType())
109 { 109 {
110 case ValueType_BinaryString: 110 case ValueType_BinaryString:
111 return dynamic_cast<const BinaryStringValue&>(value).GetContent(); 111 return dynamic_cast<const BinaryStringValue&>(value).GetContent();
112 112
1584 1584
1585 #if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1 1585 #if ORTHANC_PLUGINS_HAS_DATABASE_CONSTRAINT == 1
1586 class IndexBackend::LookupFormatter : public Orthanc::ISqlLookupFormatter 1586 class IndexBackend::LookupFormatter : public Orthanc::ISqlLookupFormatter
1587 { 1587 {
1588 private: 1588 private:
1589 Dialect dialect_; 1589 Dialect dialect_;
1590 1590 size_t count_;
1591 Dictionary dictionary_;
1592
1593 static std::string FormatParameter(size_t index)
1594 {
1595 return "p" + boost::lexical_cast<std::string>(index);
1596 }
1597
1591 public: 1598 public:
1592 LookupFormatter(Dialect dialect) : 1599 LookupFormatter(Dialect dialect) :
1593 dialect_(dialect) 1600 dialect_(dialect),
1601 count_(0)
1594 { 1602 {
1595 } 1603 }
1596 1604
1597 virtual std::string GenerateParameter(const std::string& value) 1605 virtual std::string GenerateParameter(const std::string& value)
1606 {
1607 const std::string key = FormatParameter(count_);
1608
1609 count_ ++;
1610 dictionary_.SetUtf8Value(key, value);
1611
1612 return "${" + key + "}";
1613 }
1614
1615 virtual std::string FormatResourceType(Orthanc::ResourceType level)
1616 {
1617 return boost::lexical_cast<std::string>(Orthanc::Plugins::Convert(level));
1618 }
1619
1620 virtual std::string FormatWildcardEscape()
1598 { 1621 {
1599 switch (dialect_) 1622 switch (dialect_)
1600 { 1623 {
1624 case Dialect_SQLite:
1625 case Dialect_PostgreSQL:
1626 return "ESCAPE '\\'";
1627
1601 case Dialect_MySQL: 1628 case Dialect_MySQL:
1602 break; 1629 return "ESCAPE '\\\\'";
1603
1604 case Dialect_PostgreSQL:
1605 break;
1606
1607 case Dialect_SQLite:
1608 break;
1609 1630
1610 default: 1631 default:
1611 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); 1632 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
1612 } 1633 }
1634 }
1635
1636 void PrepareStatement(DatabaseManager::StandaloneStatement& statement) const
1637 {
1638 statement.SetReadOnly(true);
1639
1640 for (size_t i = 0; i < count_; i++)
1641 {
1642 statement.SetParameterType(FormatParameter(i), ValueType_Utf8String);
1643 }
1644 }
1645
1646 const Dictionary& GetDictionary() const
1647 {
1648 return dictionary_;
1613 } 1649 }
1614 }; 1650 };
1615 #endif 1651 #endif
1616 1652
1617 1653
1620 void IndexBackend::LookupResources(const std::vector<Orthanc::DatabaseConstraint>& lookup, 1656 void IndexBackend::LookupResources(const std::vector<Orthanc::DatabaseConstraint>& lookup,
1621 OrthancPluginResourceType queryLevel, 1657 OrthancPluginResourceType queryLevel,
1622 uint32_t limit, 1658 uint32_t limit,
1623 bool requestSomeInstance) 1659 bool requestSomeInstance)
1624 { 1660 {
1661 LookupFormatter formatter(manager_.GetDialect());
1662
1625 std::string sql; 1663 std::string sql;
1626 1664 Orthanc::ISqlLookupFormatter::Apply(sql, formatter, lookup,
1627 { 1665 Orthanc::Plugins::Convert(queryLevel), limit);
1628 LookupFormatter formatter(manager_.GetDialect()); 1666
1629 Orthanc::ISqlLookupFormatter::Apply(sql, formatter, lookup, 1667 if (requestSomeInstance)
1630 Orthanc::Plugins::Convert(queryLevel), limit); 1668 {
1631 } 1669 // Composite query to find some instance if requested
1670 switch (queryLevel)
1671 {
1672 case OrthancPluginResourceType_Patient:
1673 sql = ("SELECT patients.publicId, MIN(instances.publicId) FROM (" + sql + ") patients "
1674 "INNER JOIN Resources studies ON studies.parentId = patients.internalId "
1675 "INNER JOIN Resources series ON series.parentId = studies.internalId "
1676 "INNER JOIN Resources instances ON instances.parentId = series.internalId "
1677 "GROUP BY patients.publicId");
1678 break;
1679
1680 case OrthancPluginResourceType_Study:
1681 sql = ("SELECT studies.publicId, MIN(instances.publicId) FROM (" + sql + ") studies "
1682 "INNER JOIN Resources series ON series.parentId = studies.internalId "
1683 "INNER JOIN Resources instances ON instances.parentId = series.internalId "
1684 "GROUP BY studies.publicId");
1685 break;
1686
1687 case OrthancPluginResourceType_Series:
1688 sql = ("SELECT series.publicId, MIN(instances.publicId) FROM (" + sql + ") series "
1689 "INNER JOIN Resources instances ON instances.parentId = series.internalId "
1690 "GROUP BY series.publicId");
1691 break;
1692
1693 case OrthancPluginResourceType_Instance:
1694 sql = ("SELECT instances.publicId, instances.publicId FROM (" + sql + ") instances");
1695 break;
1696
1697 default:
1698 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
1699 }
1700 }
1701
1702 DatabaseManager::StandaloneStatement statement(GetManager(), sql);
1703 formatter.PrepareStatement(statement);
1704
1705 statement.Execute(formatter.GetDictionary());
1706
1707 while (!statement.IsDone())
1708 {
1709 if (requestSomeInstance)
1710 {
1711 GetOutput().AnswerMatchingResource(ReadString(statement, 0), ReadString(statement, 1));
1712 }
1713 else
1714 {
1715 GetOutput().AnswerMatchingResource(ReadString(statement, 0));
1716 }
1717
1718 statement.Next();
1719 }
1632 } 1720 }
1633 #endif 1721 #endif
1634 } 1722 }