diff --git a/LCS/databases/PL/include/PL/Query/BinaryExprNode.h b/LCS/databases/PL/include/PL/Query/BinaryExprNode.h index 95cb3a9d2934ef0c1b71fbaaf5c050e58222e1f2..45bed3f5bb9b953cd03f5fae8887200726ceb9a2 100644 --- a/LCS/databases/PL/include/PL/Query/BinaryExprNode.h +++ b/LCS/databases/PL/include/PL/Query/BinaryExprNode.h @@ -56,8 +56,8 @@ namespace LOFAR private: - // @name The operator - const std::string itsOperand; + // @name The operation + const std::string itsOperation; // @name The operands //@{ diff --git a/LCS/databases/PL/include/PL/Query/ConstExprNode.h b/LCS/databases/PL/include/PL/Query/ConstExprNode.h index 1f91da3589d8108c939aa2a1ce5206efb8d76b4a..4acf1780592de8c5954d21689513ccf5704d4fd1 100644 --- a/LCS/databases/PL/include/PL/Query/ConstExprNode.h +++ b/LCS/databases/PL/include/PL/Query/ConstExprNode.h @@ -39,8 +39,9 @@ namespace LOFAR { //# Forward Declarations - // @defgroup ConstExprNode + // @defgroup ConstExprNode Constant Expression Nodes // @ingroup ExprNode + // // These classes represent constant expression nodes. A constant // expression is an expression that can be evaluated compile-time and // has a primitive type like int, double or string. diff --git a/LCS/databases/PL/include/PL/Query/Expr.h b/LCS/databases/PL/include/PL/Query/Expr.h index 6a0ee817e0eedaa439b2dbbe411f05a0d4f9ea39..f8934b5a2af4d57c3de2362c57d09e7ce1b24d85 100644 --- a/LCS/databases/PL/include/PL/Query/Expr.h +++ b/LCS/databases/PL/include/PL/Query/Expr.h @@ -37,12 +37,12 @@ namespace LOFAR { namespace PL { + template<typename T> class Collection; + namespace Query { - //# Forward Declarations - - // An Expr represents the WHERE clause of a query. + // This class represents the WHERE clause of a query. class Expr { public: @@ -53,6 +53,7 @@ namespace LOFAR Expr(int value); Expr(double value); Expr(const std::string& value); + Expr(const char* const value); //@} // Construct an Expr from an ExprNode pointer. @@ -67,6 +68,27 @@ namespace LOFAR Expr operator! () const; //@} + //@{ + // The BETWEEN operator is used to test if a value is within an + // interval. + Expr between(const Expr& lhs, const Expr& rhs) const; + Expr notBetween(const Expr& lhs, const Expr& rhs) const; + //@} + + //@{ + // The IN operator is used to test if an expression is contained in a + // set of expressions. + Expr in (const Collection<Expr>& set) const; + Expr notIn(const Collection<Expr>& set) const; + //@} + + //@{ + // The LIKE operator is used to test if a value has a match with a + // pattern expression. + Expr like(const Expr& exp) const; + Expr notLike(const Expr& exp) const; + //@} + private: // @name Arithmetic operators diff --git a/LCS/databases/PL/include/PL/Query/ExprNode.h b/LCS/databases/PL/include/PL/Query/ExprNode.h index 5c4b9cd3b559621d2a30d96414ed7b35c58e1559..20910394667fa736bf8e66dd1b26f008ce9f8074 100644 --- a/LCS/databases/PL/include/PL/Query/ExprNode.h +++ b/LCS/databases/PL/include/PL/Query/ExprNode.h @@ -39,8 +39,8 @@ namespace LOFAR //# Forward Declarations class Expr; - // @defgroup ExprNode - + // @defgroup ExprNode Expression Nodes + // // ExprNode is an abstract base class that represents the node of an // expression query. We will need to derive specific expression node // classes (e.g. ExprNodeBinary) from it. diff --git a/LCS/databases/PL/include/PL/Query/SQLExprNode.h b/LCS/databases/PL/include/PL/Query/SQLExprNode.h index 68aa76ce2ce94dc4094763b5ca623c2187732fdf..b8a08cb99ac675f43ff11be235a459e04b777ee1 100644 --- a/LCS/databases/PL/include/PL/Query/SQLExprNode.h +++ b/LCS/databases/PL/include/PL/Query/SQLExprNode.h @@ -83,6 +83,8 @@ namespace LOFAR // expression that takes one operator (IN or NOT IN) and two // operands. It is used to check whether the first operand is present in // the second operand. + // \note When \c rhs contains no elements only the \c lhs will be + // returned when you invoke print() on InExprNode. class InExprNode : public ExprNode { public: @@ -116,7 +118,22 @@ namespace LOFAR // The user-supplied pattern can contain the wildcards "*" and "?", // where "*" means any number of characters, and "?" means exactly one // character. These wildcards will be translated to their - // SQL-equivalents "%" and "_" respectively. + // SQL-equivalents "%" and "_" respectively. + // + // We will use the backslash character (\) as escape character in the + // LIKE clause. As the backslash character needs to be escaped itself, + // we always have to provide two backslash characters as the escape + // token. + // + // Hence we get the following substitution scheme: + // \verbatim + // '*' --> '%' + // '?' --> '_' + // '\*' --> '*' + // '\?' --> '?' + // '_' --> '\\_' + // '%' --> '\\%' + // \endverbatim class LikeExprNode : public ExprNode { public: diff --git a/LCS/databases/PL/include/PL/Query/UnaryExprNode.h b/LCS/databases/PL/include/PL/Query/UnaryExprNode.h index 4e91e6ea8c7aacb17f7db99966e5f06cda27b498..552eeccbbe280d3eebd26eec167492b36cc51de7 100644 --- a/LCS/databases/PL/include/PL/Query/UnaryExprNode.h +++ b/LCS/databases/PL/include/PL/Query/UnaryExprNode.h @@ -48,6 +48,9 @@ namespace LOFAR UnaryExprNode(const std::string& oper, const Expr& value); +// UnaryExprNode(const std::string& oper, +// const ExprNodeSet& set); + virtual ~UnaryExprNode(); virtual void print(std::ostream& os); diff --git a/LCS/databases/PL/src/Query/BinaryExprNode.cc b/LCS/databases/PL/src/Query/BinaryExprNode.cc index 68ab4093fa7bb4cb43bfec3d2b0f58986b262475..3937d261280485a46cce3f705830f8b1d2467f9b 100644 --- a/LCS/databases/PL/src/Query/BinaryExprNode.cc +++ b/LCS/databases/PL/src/Query/BinaryExprNode.cc @@ -32,16 +32,18 @@ namespace LOFAR BinaryExprNode::BinaryExprNode(const std::string& oper, const Expr& lhs, const Expr& rhs) : - itsOperand(oper), + itsOperation(oper), itsLeft(lhs), itsRight(rhs) { } - BinaryExprNode::~BinaryExprNode() {} + BinaryExprNode::~BinaryExprNode() + { + } void BinaryExprNode::print(std::ostream& os) { - os << "(" << itsLeft << itsOperand << itsRight << ")"; + os << "(" << itsLeft << itsOperation << itsRight << ")"; } } // namespace Query diff --git a/LCS/databases/PL/src/Query/BinaryExprNode.h b/LCS/databases/PL/src/Query/BinaryExprNode.h index 95cb3a9d2934ef0c1b71fbaaf5c050e58222e1f2..45bed3f5bb9b953cd03f5fae8887200726ceb9a2 100644 --- a/LCS/databases/PL/src/Query/BinaryExprNode.h +++ b/LCS/databases/PL/src/Query/BinaryExprNode.h @@ -56,8 +56,8 @@ namespace LOFAR private: - // @name The operator - const std::string itsOperand; + // @name The operation + const std::string itsOperation; // @name The operands //@{ diff --git a/LCS/databases/PL/src/Query/ConstExprNode.h b/LCS/databases/PL/src/Query/ConstExprNode.h index 1f91da3589d8108c939aa2a1ce5206efb8d76b4a..4acf1780592de8c5954d21689513ccf5704d4fd1 100644 --- a/LCS/databases/PL/src/Query/ConstExprNode.h +++ b/LCS/databases/PL/src/Query/ConstExprNode.h @@ -39,8 +39,9 @@ namespace LOFAR { //# Forward Declarations - // @defgroup ConstExprNode + // @defgroup ConstExprNode Constant Expression Nodes // @ingroup ExprNode + // // These classes represent constant expression nodes. A constant // expression is an expression that can be evaluated compile-time and // has a primitive type like int, double or string. diff --git a/LCS/databases/PL/src/Query/Expr.cc b/LCS/databases/PL/src/Query/Expr.cc index 680b55aac1333187baf8ac919d1f95963a088abc..300e04797f3b0874902b4797a1ae6da743f783d2 100644 --- a/LCS/databases/PL/src/Query/Expr.cc +++ b/LCS/databases/PL/src/Query/Expr.cc @@ -24,6 +24,7 @@ #include <PL/Query/ConstExprNode.h> #include <PL/Query/UnaryExprNode.h> #include <PL/Query/BinaryExprNode.h> +#include <PL/Query/SQLExprNode.h> #include <iostream> using std::ostream; @@ -56,6 +57,11 @@ namespace LOFAR itsNode(new StringExprNode(value)) { } + + Expr::Expr(const char* const value) : + itsNode(new StringExprNode(value)) + { + } Expr::Expr(ExprNode* const node) : itsNode(node) @@ -79,7 +85,7 @@ namespace LOFAR Expr Expr::operator! () const { - return new UnaryExprNode("NOT", *this); + return new UnaryExprNode("NOT ", *this); } @@ -149,12 +155,47 @@ namespace LOFAR Expr operator&& (const Expr& lhs, const Expr& rhs) { - return new BinaryExprNode("AND", lhs, rhs); + return new BinaryExprNode(" AND ", lhs, rhs); } Expr operator|| (const Expr& lhs, const Expr& rhs) { - return new BinaryExprNode("OR", lhs, rhs); + return new BinaryExprNode(" OR ", lhs, rhs); + } + + + /////////////////////////////////////////////////////////////////// + // SQL-like operators // + /////////////////////////////////////////////////////////////////// + + Expr Expr::between (const Expr& lhs, const Expr& rhs) const + { + return new BetweenExprNode(" BETWEEN ", *this, lhs, rhs); + } + + Expr Expr::notBetween (const Expr& lhs, const Expr& rhs) const + { + return new BetweenExprNode(" NOT BETWEEN ", *this, lhs, rhs); + } + + Expr Expr::in (const Collection<Expr>& set) const + { + return new InExprNode(" IN ", *this, set); + } + + Expr Expr::notIn (const Collection<Expr>& set) const + { + return new InExprNode(" NOT IN ", *this, set); + } + + Expr Expr::like (const Expr& exp) const + { + return new LikeExprNode(" LIKE ", *this, exp); + } + + Expr Expr::notLike (const Expr& exp) const + { + return new LikeExprNode(" NOT LIKE ", *this, exp); } diff --git a/LCS/databases/PL/src/Query/Expr.h b/LCS/databases/PL/src/Query/Expr.h index 6a0ee817e0eedaa439b2dbbe411f05a0d4f9ea39..f8934b5a2af4d57c3de2362c57d09e7ce1b24d85 100644 --- a/LCS/databases/PL/src/Query/Expr.h +++ b/LCS/databases/PL/src/Query/Expr.h @@ -37,12 +37,12 @@ namespace LOFAR { namespace PL { + template<typename T> class Collection; + namespace Query { - //# Forward Declarations - - // An Expr represents the WHERE clause of a query. + // This class represents the WHERE clause of a query. class Expr { public: @@ -53,6 +53,7 @@ namespace LOFAR Expr(int value); Expr(double value); Expr(const std::string& value); + Expr(const char* const value); //@} // Construct an Expr from an ExprNode pointer. @@ -67,6 +68,27 @@ namespace LOFAR Expr operator! () const; //@} + //@{ + // The BETWEEN operator is used to test if a value is within an + // interval. + Expr between(const Expr& lhs, const Expr& rhs) const; + Expr notBetween(const Expr& lhs, const Expr& rhs) const; + //@} + + //@{ + // The IN operator is used to test if an expression is contained in a + // set of expressions. + Expr in (const Collection<Expr>& set) const; + Expr notIn(const Collection<Expr>& set) const; + //@} + + //@{ + // The LIKE operator is used to test if a value has a match with a + // pattern expression. + Expr like(const Expr& exp) const; + Expr notLike(const Expr& exp) const; + //@} + private: // @name Arithmetic operators diff --git a/LCS/databases/PL/src/Query/ExprNode.h b/LCS/databases/PL/src/Query/ExprNode.h index 5c4b9cd3b559621d2a30d96414ed7b35c58e1559..20910394667fa736bf8e66dd1b26f008ce9f8074 100644 --- a/LCS/databases/PL/src/Query/ExprNode.h +++ b/LCS/databases/PL/src/Query/ExprNode.h @@ -39,8 +39,8 @@ namespace LOFAR //# Forward Declarations class Expr; - // @defgroup ExprNode - + // @defgroup ExprNode Expression Nodes + // // ExprNode is an abstract base class that represents the node of an // expression query. We will need to derive specific expression node // classes (e.g. ExprNodeBinary) from it. diff --git a/LCS/databases/PL/src/Query/SQLExprNode.cc b/LCS/databases/PL/src/Query/SQLExprNode.cc index 6a19816a5fbd1b01b520bc90a8e77b0d73c27e2d..2a7d30f815c6f24184703c462b1d36e7d797ae53 100644 --- a/LCS/databases/PL/src/Query/SQLExprNode.cc +++ b/LCS/databases/PL/src/Query/SQLExprNode.cc @@ -67,18 +67,18 @@ namespace LOFAR void InExprNode::print(std::ostream& os) { - ostringstream oss; - Collection<Expr>::const_iterator it; - for (it = itsRight.begin(); it != itsRight.end(); ++it) { - oss << *it << ","; - } - // Convert oss to a string; strip last comma if there is one - string s(oss.str()); - string::size_type idx; - if ((idx = s.rfind(",")) != string::npos) { - s.erase(idx); + os << "(" << itsLeft; + if (!itsRight.empty()) { + ostringstream oss; + Collection<Expr>::const_iterator it; + for (it = itsRight.begin(); it != itsRight.end(); ++it) { + oss << *it << ","; + } + string s(oss.str()); // convert oss to a string + s.erase(s.size()-1); // strip trailing comma + os << itsOperation << "(" << s << ")"; } - os << "(" << itsLeft << itsOperation << "(" << s << "))"; + os << ")"; } @@ -95,18 +95,42 @@ namespace LOFAR void LikeExprNode::print(std::ostream& os) { - // Scan the pattern expression for occurrences of "*" and "?". - // We have to check whether these characters are escaped! - std::string s; - bool isEscaped = false; -// for(string::size_type idx = 0; idx < itsRight.size(); ++idx) { -// isEscaped = (itsRight[idx] == '\\'); -// if (isEscaped) { - -// } -// } + ostringstream oss; + oss << itsRight; + string rhs(oss.str()); + string pattern; + + // Scan the pattern expression in itsRight for occurrences of wildcard + // characters and make the proper substitutions. + for(string::const_iterator it = rhs.begin(); it != rhs.end(); ++it) { + switch (*it) { + case '*': + pattern += "%"; + break; + case '?': + pattern += "_"; + break; + case '%': + pattern += "\\\\%"; + break; + case '_': + pattern += "\\\\_"; + break; + case '\\': + if (++it != rhs.end()) + if (*it == '\\') pattern += "\\\\\\\\"; + else pattern += *it; + break; + default: + pattern += *it; + break; + } + } + + os << "(" << itsLeft << itsOperation << pattern << " ESCAPE '\\\\')"; } + } // namespace Query } // namespace PL diff --git a/LCS/databases/PL/src/Query/SQLExprNode.h b/LCS/databases/PL/src/Query/SQLExprNode.h index 68aa76ce2ce94dc4094763b5ca623c2187732fdf..b8a08cb99ac675f43ff11be235a459e04b777ee1 100644 --- a/LCS/databases/PL/src/Query/SQLExprNode.h +++ b/LCS/databases/PL/src/Query/SQLExprNode.h @@ -83,6 +83,8 @@ namespace LOFAR // expression that takes one operator (IN or NOT IN) and two // operands. It is used to check whether the first operand is present in // the second operand. + // \note When \c rhs contains no elements only the \c lhs will be + // returned when you invoke print() on InExprNode. class InExprNode : public ExprNode { public: @@ -116,7 +118,22 @@ namespace LOFAR // The user-supplied pattern can contain the wildcards "*" and "?", // where "*" means any number of characters, and "?" means exactly one // character. These wildcards will be translated to their - // SQL-equivalents "%" and "_" respectively. + // SQL-equivalents "%" and "_" respectively. + // + // We will use the backslash character (\) as escape character in the + // LIKE clause. As the backslash character needs to be escaped itself, + // we always have to provide two backslash characters as the escape + // token. + // + // Hence we get the following substitution scheme: + // \verbatim + // '*' --> '%' + // '?' --> '_' + // '\*' --> '*' + // '\?' --> '?' + // '_' --> '\\_' + // '%' --> '\\%' + // \endverbatim class LikeExprNode : public ExprNode { public: diff --git a/LCS/databases/PL/src/Query/UnaryExprNode.cc b/LCS/databases/PL/src/Query/UnaryExprNode.cc index 343f8cdee74156680b87843d22efe17ec3accc45..d68350e9f92ad3b3dd4bc52a3792c7e8acabe470 100644 --- a/LCS/databases/PL/src/Query/UnaryExprNode.cc +++ b/LCS/databases/PL/src/Query/UnaryExprNode.cc @@ -42,7 +42,7 @@ namespace LOFAR void UnaryExprNode::print(std::ostream& os) { - os << itsOperation << "(" << itsOperand << ")"; + os << "(" << itsOperation << itsOperand << ")"; } } // namespace Query diff --git a/LCS/databases/PL/src/Query/UnaryExprNode.h b/LCS/databases/PL/src/Query/UnaryExprNode.h index 4e91e6ea8c7aacb17f7db99966e5f06cda27b498..552eeccbbe280d3eebd26eec167492b36cc51de7 100644 --- a/LCS/databases/PL/src/Query/UnaryExprNode.h +++ b/LCS/databases/PL/src/Query/UnaryExprNode.h @@ -48,6 +48,9 @@ namespace LOFAR UnaryExprNode(const std::string& oper, const Expr& value); +// UnaryExprNode(const std::string& oper, +// const ExprNodeSet& set); + virtual ~UnaryExprNode(); virtual void print(std::ostream& os);