Skip to content
Snippets Groups Projects
Commit d409bb80 authored by Marcel Loose's avatar Marcel Loose :sunglasses:
Browse files

%[ER: 65]%

Added SQL-like operator like BETWEEN, IN, and LIKE. Fixed couple of bugs.
parent e51acccd
No related branches found
No related tags found
No related merge requests found
Showing
with 199 additions and 46 deletions
...@@ -56,8 +56,8 @@ namespace LOFAR ...@@ -56,8 +56,8 @@ namespace LOFAR
private: private:
// @name The operator // @name The operation
const std::string itsOperand; const std::string itsOperation;
// @name The operands // @name The operands
//@{ //@{
......
...@@ -39,8 +39,9 @@ namespace LOFAR ...@@ -39,8 +39,9 @@ namespace LOFAR
{ {
//# Forward Declarations //# Forward Declarations
// @defgroup ConstExprNode // @defgroup ConstExprNode Constant Expression Nodes
// @ingroup ExprNode // @ingroup ExprNode
//
// These classes represent constant expression nodes. A constant // These classes represent constant expression nodes. A constant
// expression is an expression that can be evaluated compile-time and // expression is an expression that can be evaluated compile-time and
// has a primitive type like int, double or string. // has a primitive type like int, double or string.
......
...@@ -37,12 +37,12 @@ namespace LOFAR ...@@ -37,12 +37,12 @@ namespace LOFAR
{ {
namespace PL namespace PL
{ {
template<typename T> class Collection;
namespace Query namespace Query
{ {
//# Forward Declarations // This class represents the WHERE clause of a query.
// An Expr represents the WHERE clause of a query.
class Expr class Expr
{ {
public: public:
...@@ -53,6 +53,7 @@ namespace LOFAR ...@@ -53,6 +53,7 @@ namespace LOFAR
Expr(int value); Expr(int value);
Expr(double value); Expr(double value);
Expr(const std::string& value); Expr(const std::string& value);
Expr(const char* const value);
//@} //@}
// Construct an Expr from an ExprNode pointer. // Construct an Expr from an ExprNode pointer.
...@@ -67,6 +68,27 @@ namespace LOFAR ...@@ -67,6 +68,27 @@ namespace LOFAR
Expr operator! () const; 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: private:
// @name Arithmetic operators // @name Arithmetic operators
......
...@@ -39,8 +39,8 @@ namespace LOFAR ...@@ -39,8 +39,8 @@ namespace LOFAR
//# Forward Declarations //# Forward Declarations
class Expr; class Expr;
// @defgroup ExprNode // @defgroup ExprNode Expression Nodes
//
// ExprNode is an abstract base class that represents the node of an // ExprNode is an abstract base class that represents the node of an
// expression query. We will need to derive specific expression node // expression query. We will need to derive specific expression node
// classes (e.g. ExprNodeBinary) from it. // classes (e.g. ExprNodeBinary) from it.
......
...@@ -83,6 +83,8 @@ namespace LOFAR ...@@ -83,6 +83,8 @@ namespace LOFAR
// expression that takes one operator (IN or NOT IN) and two // expression that takes one operator (IN or NOT IN) and two
// operands. It is used to check whether the first operand is present in // operands. It is used to check whether the first operand is present in
// the second operand. // 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 class InExprNode : public ExprNode
{ {
public: public:
...@@ -116,7 +118,22 @@ namespace LOFAR ...@@ -116,7 +118,22 @@ namespace LOFAR
// The user-supplied pattern can contain the wildcards "*" and "?", // The user-supplied pattern can contain the wildcards "*" and "?",
// where "*" means any number of characters, and "?" means exactly one // where "*" means any number of characters, and "?" means exactly one
// character. These wildcards will be translated to their // 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 class LikeExprNode : public ExprNode
{ {
public: public:
......
...@@ -48,6 +48,9 @@ namespace LOFAR ...@@ -48,6 +48,9 @@ namespace LOFAR
UnaryExprNode(const std::string& oper, UnaryExprNode(const std::string& oper,
const Expr& value); const Expr& value);
// UnaryExprNode(const std::string& oper,
// const ExprNodeSet& set);
virtual ~UnaryExprNode(); virtual ~UnaryExprNode();
virtual void print(std::ostream& os); virtual void print(std::ostream& os);
......
...@@ -32,16 +32,18 @@ namespace LOFAR ...@@ -32,16 +32,18 @@ namespace LOFAR
BinaryExprNode::BinaryExprNode(const std::string& oper, BinaryExprNode::BinaryExprNode(const std::string& oper,
const Expr& lhs, const Expr& rhs) : const Expr& lhs, const Expr& rhs) :
itsOperand(oper), itsOperation(oper),
itsLeft(lhs), itsRight(rhs) itsLeft(lhs), itsRight(rhs)
{ {
} }
BinaryExprNode::~BinaryExprNode() {} BinaryExprNode::~BinaryExprNode()
{
}
void BinaryExprNode::print(std::ostream& os) void BinaryExprNode::print(std::ostream& os)
{ {
os << "(" << itsLeft << itsOperand << itsRight << ")"; os << "(" << itsLeft << itsOperation << itsRight << ")";
} }
} // namespace Query } // namespace Query
......
...@@ -56,8 +56,8 @@ namespace LOFAR ...@@ -56,8 +56,8 @@ namespace LOFAR
private: private:
// @name The operator // @name The operation
const std::string itsOperand; const std::string itsOperation;
// @name The operands // @name The operands
//@{ //@{
......
...@@ -39,8 +39,9 @@ namespace LOFAR ...@@ -39,8 +39,9 @@ namespace LOFAR
{ {
//# Forward Declarations //# Forward Declarations
// @defgroup ConstExprNode // @defgroup ConstExprNode Constant Expression Nodes
// @ingroup ExprNode // @ingroup ExprNode
//
// These classes represent constant expression nodes. A constant // These classes represent constant expression nodes. A constant
// expression is an expression that can be evaluated compile-time and // expression is an expression that can be evaluated compile-time and
// has a primitive type like int, double or string. // has a primitive type like int, double or string.
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <PL/Query/ConstExprNode.h> #include <PL/Query/ConstExprNode.h>
#include <PL/Query/UnaryExprNode.h> #include <PL/Query/UnaryExprNode.h>
#include <PL/Query/BinaryExprNode.h> #include <PL/Query/BinaryExprNode.h>
#include <PL/Query/SQLExprNode.h>
#include <iostream> #include <iostream>
using std::ostream; using std::ostream;
...@@ -56,6 +57,11 @@ namespace LOFAR ...@@ -56,6 +57,11 @@ namespace LOFAR
itsNode(new StringExprNode(value)) itsNode(new StringExprNode(value))
{ {
} }
Expr::Expr(const char* const value) :
itsNode(new StringExprNode(value))
{
}
Expr::Expr(ExprNode* const node) : Expr::Expr(ExprNode* const node) :
itsNode(node) itsNode(node)
...@@ -79,7 +85,7 @@ namespace LOFAR ...@@ -79,7 +85,7 @@ namespace LOFAR
Expr Expr::operator! () const Expr Expr::operator! () const
{ {
return new UnaryExprNode("NOT", *this); return new UnaryExprNode("NOT ", *this);
} }
...@@ -149,12 +155,47 @@ namespace LOFAR ...@@ -149,12 +155,47 @@ namespace LOFAR
Expr operator&& (const Expr& lhs, const Expr& rhs) 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) 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);
} }
......
...@@ -37,12 +37,12 @@ namespace LOFAR ...@@ -37,12 +37,12 @@ namespace LOFAR
{ {
namespace PL namespace PL
{ {
template<typename T> class Collection;
namespace Query namespace Query
{ {
//# Forward Declarations // This class represents the WHERE clause of a query.
// An Expr represents the WHERE clause of a query.
class Expr class Expr
{ {
public: public:
...@@ -53,6 +53,7 @@ namespace LOFAR ...@@ -53,6 +53,7 @@ namespace LOFAR
Expr(int value); Expr(int value);
Expr(double value); Expr(double value);
Expr(const std::string& value); Expr(const std::string& value);
Expr(const char* const value);
//@} //@}
// Construct an Expr from an ExprNode pointer. // Construct an Expr from an ExprNode pointer.
...@@ -67,6 +68,27 @@ namespace LOFAR ...@@ -67,6 +68,27 @@ namespace LOFAR
Expr operator! () const; 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: private:
// @name Arithmetic operators // @name Arithmetic operators
......
...@@ -39,8 +39,8 @@ namespace LOFAR ...@@ -39,8 +39,8 @@ namespace LOFAR
//# Forward Declarations //# Forward Declarations
class Expr; class Expr;
// @defgroup ExprNode // @defgroup ExprNode Expression Nodes
//
// ExprNode is an abstract base class that represents the node of an // ExprNode is an abstract base class that represents the node of an
// expression query. We will need to derive specific expression node // expression query. We will need to derive specific expression node
// classes (e.g. ExprNodeBinary) from it. // classes (e.g. ExprNodeBinary) from it.
......
...@@ -67,18 +67,18 @@ namespace LOFAR ...@@ -67,18 +67,18 @@ namespace LOFAR
void InExprNode::print(std::ostream& os) void InExprNode::print(std::ostream& os)
{ {
ostringstream oss; os << "(" << itsLeft;
Collection<Expr>::const_iterator it; if (!itsRight.empty()) {
for (it = itsRight.begin(); it != itsRight.end(); ++it) { ostringstream oss;
oss << *it << ","; Collection<Expr>::const_iterator it;
} for (it = itsRight.begin(); it != itsRight.end(); ++it) {
// Convert oss to a string; strip last comma if there is one oss << *it << ",";
string s(oss.str()); }
string::size_type idx; string s(oss.str()); // convert oss to a string
if ((idx = s.rfind(",")) != string::npos) { s.erase(s.size()-1); // strip trailing comma
s.erase(idx); os << itsOperation << "(" << s << ")";
} }
os << "(" << itsLeft << itsOperation << "(" << s << "))"; os << ")";
} }
...@@ -95,18 +95,42 @@ namespace LOFAR ...@@ -95,18 +95,42 @@ namespace LOFAR
void LikeExprNode::print(std::ostream& os) void LikeExprNode::print(std::ostream& os)
{ {
// Scan the pattern expression for occurrences of "*" and "?". ostringstream oss;
// We have to check whether these characters are escaped! oss << itsRight;
std::string s; string rhs(oss.str());
bool isEscaped = false; string pattern;
// for(string::size_type idx = 0; idx < itsRight.size(); ++idx) {
// isEscaped = (itsRight[idx] == '\\'); // Scan the pattern expression in itsRight for occurrences of wildcard
// if (isEscaped) { // 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 Query
} // namespace PL } // namespace PL
......
...@@ -83,6 +83,8 @@ namespace LOFAR ...@@ -83,6 +83,8 @@ namespace LOFAR
// expression that takes one operator (IN or NOT IN) and two // expression that takes one operator (IN or NOT IN) and two
// operands. It is used to check whether the first operand is present in // operands. It is used to check whether the first operand is present in
// the second operand. // 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 class InExprNode : public ExprNode
{ {
public: public:
...@@ -116,7 +118,22 @@ namespace LOFAR ...@@ -116,7 +118,22 @@ namespace LOFAR
// The user-supplied pattern can contain the wildcards "*" and "?", // The user-supplied pattern can contain the wildcards "*" and "?",
// where "*" means any number of characters, and "?" means exactly one // where "*" means any number of characters, and "?" means exactly one
// character. These wildcards will be translated to their // 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 class LikeExprNode : public ExprNode
{ {
public: public:
......
...@@ -42,7 +42,7 @@ namespace LOFAR ...@@ -42,7 +42,7 @@ namespace LOFAR
void UnaryExprNode::print(std::ostream& os) void UnaryExprNode::print(std::ostream& os)
{ {
os << itsOperation << "(" << itsOperand << ")"; os << "(" << itsOperation << itsOperand << ")";
} }
} // namespace Query } // namespace Query
......
...@@ -48,6 +48,9 @@ namespace LOFAR ...@@ -48,6 +48,9 @@ namespace LOFAR
UnaryExprNode(const std::string& oper, UnaryExprNode(const std::string& oper,
const Expr& value); const Expr& value);
// UnaryExprNode(const std::string& oper,
// const ExprNodeSet& set);
virtual ~UnaryExprNode(); virtual ~UnaryExprNode();
virtual void print(std::ostream& os); virtual void print(std::ostream& os);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment