// file : odb/pgsql/query.hxx // copyright : Copyright (c) 2009-2012 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_PGSQL_QUERY_HXX #define ODB_PGSQL_QUERY_HXX #include #include #include #include // std::size_t #include #include #include #include #include #include #include #include #include #include namespace odb { namespace pgsql { template class val_bind { public: explicit val_bind (const T& v): val (v) {} const T& val; }; template class ref_bind { public: explicit ref_bind (const T& r): ref (r) {} const T& ref; }; struct LIBODB_PGSQL_EXPORT query_param: details::shared_base { typedef pgsql::bind bind_type; virtual ~query_param (); bool reference () const { return value_ != 0; } virtual bool init () = 0; virtual void bind (bind_type*) = 0; virtual unsigned int oid () const = 0; protected: query_param (const void* value) : value_ (value) { } protected: const void* value_; }; // // template struct query_column; class LIBODB_PGSQL_EXPORT query { public: struct clause_part { enum kind_type { column, param, native, boolean }; clause_part (kind_type k): kind (k) {} clause_part (kind_type k, const std::string& p): kind (k), part (p) {} clause_part (bool p): kind (boolean), bool_part (p) {} kind_type kind; std::string part; // If kind is param, then part is conversion expr. bool bool_part; }; query () : binding_ (0, 0), native_binding_ (0, 0, 0, 0) { } // True or false literal. // explicit query (bool v) : binding_ (0, 0), native_binding_ (0, 0, 0, 0) { clause_.push_back (clause_part (v)); } explicit query (const char* native) : binding_ (0, 0), native_binding_ (0, 0, 0, 0) { clause_.push_back (clause_part (clause_part::native, native)); } explicit query (const std::string& native) : binding_ (0, 0), native_binding_ (0, 0, 0, 0) { clause_.push_back (clause_part (clause_part::native, native)); } query (const char* table, const char* column) : binding_ (0, 0), native_binding_ (0, 0, 0, 0) { append (table, column); } template explicit query (val_bind v) : binding_ (0, 0), native_binding_ (0, 0, 0, 0) { append::db_type_id> ( v, details::conversion::to ()); } template explicit query (ref_bind r) : binding_ (0, 0), native_binding_ (0, 0, 0, 0) { append::db_type_id> ( r, details::conversion::to ()); } template query (const query_column&); query (const query&); query& operator= (const query&); public: std::string clause () const; const char* clause_prefix () const; native_binding& parameters_binding () const; const unsigned int* parameter_types () const { return types_.empty () ? 0 : &types_[0]; } std::size_t parameter_count () const { return parameters_.size (); } public: bool empty () const { return clause_.empty (); } static const query true_expr; bool const_true () const { return clause_.size () == 1 && clause_.front ().kind == clause_part::boolean && clause_.front ().bool_part; } void optimize (); public: template static val_bind _val (const T& x) { return val_bind (x); } template static ref_bind _ref (const T& x) { return ref_bind (x); } public: query& operator+= (const query&); query& operator+= (const std::string& q) { append (q); return *this; } template query& operator+= (val_bind v) { append::db_type_id> ( v, details::conversion::to ()); return *this; } template query& operator+= (ref_bind r) { append::db_type_id> ( r, details::conversion::to ()); return *this; } public: template void append (val_bind, const char* conv); template void append (ref_bind, const char* conv); void append (const std::string& native); void append (const char* table, const char* column); private: void add (details::shared_ptr, const char* conv); private: typedef std::vector clause_type; typedef std::vector > parameters_type; clause_type clause_; parameters_type parameters_; mutable std::vector bind_; mutable binding binding_; std::vector values_; std::vector lengths_; std::vector formats_; std::vector types_; mutable native_binding native_binding_; }; inline query operator+ (const query& x, const query& y) { query r (x); r += y; return r; } template inline query operator+ (const query& q, val_bind b) { query r (q); r += b; return r; } template inline query operator+ (const query& q, ref_bind b) { query r (q); r += b; return r; } template inline query operator+ (val_bind b, const query& q) { query r; r += b; r += q; return r; } template inline query operator+ (ref_bind b, const query& q) { query r; r += b; r += q; return r; } inline query operator+ (const query& q, const std::string& s) { query r (q); r += s; return r; } inline query operator+ (const std::string& s, const query& q) { query r (s); r += q; return r; } template inline query operator+ (const std::string& s, val_bind b) { query r (s); r += b; return r; } template inline query operator+ (const std::string& s, ref_bind b) { query r (s); r += b; return r; } template inline query operator+ (val_bind b, const std::string& s) { query r; r += b; r += s; return r; } template inline query operator+ (ref_bind b, const std::string& s) { query r; r += b; r += s; return r; } LIBODB_PGSQL_EXPORT query operator&& (const query&, const query&); LIBODB_PGSQL_EXPORT query operator|| (const query&, const query&); LIBODB_PGSQL_EXPORT query operator! (const query&); // query_column // template class copy_bind: public val_bind { public: explicit copy_bind (const T2& v): val_bind (val), val (v) {} const T val; }; template const T& type_instance (); template struct query_column { // Note that we keep shallow copies of the table, column, and conversion // expression. The latter can be NULL. // query_column (const char* table, const char* column, const char* conv) : table_ (table), column_ (column), conversion_ (conv) { } const char* table () const { return table_; } const char* column () const { return column_; } // Can be NULL. // const char* conversion () const { return conversion_; } // is_null, is_not_null // public: query is_null () const { query q (table_, column_); q += "IS NULL"; return q; } query is_not_null () const { query q (table_, column_); q += "IS NOT NULL"; return q; } // in // public: query in (const T&, const T&) const; query in (const T&, const T&, const T&) const; query in (const T&, const T&, const T&, const T&) const; query in (const T&, const T&, const T&, const T&, const T&) const; template query in_range (I begin, I end) const; // = // public: query equal (const T& v) const { return equal (val_bind (v)); } query equal (val_bind v) const { query q (table_, column_); q += "="; q.append (v, conversion_); return q; } template query equal (val_bind v) const { copy_bind c (v.val); return equal (c); } query equal (ref_bind r) const { query q (table_, column_); q += "="; q.append (r, conversion_); return q; } friend query operator== (const query_column& c, const T& v) { return c.equal (v); } friend query operator== (const T& v, const query_column& c) { return c.equal (v); } friend query operator== (const query_column& c, val_bind v) { return c.equal (v); } friend query operator== (val_bind v, const query_column& c) { return c.equal (v); } template friend query operator== (const query_column& c, val_bind v) { return c.equal (v); } template friend query operator== (val_bind v, const query_column& c) { return c.equal (v); } friend query operator== (const query_column& c, ref_bind r) { return c.equal (r); } friend query operator== (ref_bind r, const query_column& c) { return c.equal (r); } // != // public: query unequal (const T& v) const { return unequal (val_bind (v)); } query unequal (val_bind v) const { query q (table_, column_); q += "!="; q.append (v, conversion_); return q; } template query unequal (val_bind v) const { copy_bind c (v.val); return unequal (c); } query unequal (ref_bind r) const { query q (table_, column_); q += "!="; q.append (r, conversion_); return q; } friend query operator!= (const query_column& c, const T& v) { return c.unequal (v); } friend query operator!= (const T& v, const query_column& c) { return c.unequal (v); } friend query operator!= (const query_column& c, val_bind v) { return c.unequal (v); } friend query operator!= (val_bind v, const query_column& c) { return c.unequal (v); } template friend query operator!= (const query_column& c, val_bind v) { return c.unequal (v); } template friend query operator!= (val_bind v, const query_column& c) { return c.unequal (v); } friend query operator!= (const query_column& c, ref_bind r) { return c.unequal (r); } friend query operator!= (ref_bind r, const query_column& c) { return c.unequal (r); } // < // public: query less (const T& v) const { return less (val_bind (v)); } query less (val_bind v) const { query q (table_, column_); q += "<"; q.append (v, conversion_); return q; } template query less (val_bind v) const { copy_bind c (v.val); return less (c); } query less (ref_bind r) const { query q (table_, column_); q += "<"; q.append (r, conversion_); return q; } friend query operator< (const query_column& c, const T& v) { return c.less (v); } friend query operator< (const T& v, const query_column& c) { return c.greater (v); } friend query operator< (const query_column& c, val_bind v) { return c.less (v); } friend query operator< (val_bind v, const query_column& c) { return c.greater (v); } template friend query operator< (const query_column& c, val_bind v) { return c.less (v); } template friend query operator< (val_bind v, const query_column& c) { return c.greater (v); } friend query operator< (const query_column& c, ref_bind r) { return c.less (r); } friend query operator< (ref_bind r, const query_column& c) { return c.greater (r); } // > // public: query greater (const T& v) const { return greater (val_bind (v)); } query greater (val_bind v) const { query q (table_, column_); q += ">"; q.append (v, conversion_); return q; } template query greater (val_bind v) const { copy_bind c (v.val); return greater (c); } query greater (ref_bind r) const { query q (table_, column_); q += ">"; q.append (r, conversion_); return q; } friend query operator> (const query_column& c, const T& v) { return c.greater (v); } friend query operator> (const T& v, const query_column& c) { return c.less (v); } friend query operator> (const query_column& c, val_bind v) { return c.greater (v); } friend query operator> (val_bind v, const query_column& c) { return c.less (v); } template friend query operator> (const query_column& c, val_bind v) { return c.greater (v); } template friend query operator> (val_bind v, const query_column& c) { return c.less (v); } friend query operator> (const query_column& c, ref_bind r) { return c.greater (r); } friend query operator> (ref_bind r, const query_column& c) { return c.less (r); } // <= // public: query less_equal (const T& v) const { return less_equal (val_bind (v)); } query less_equal (val_bind v) const { query q (table_, column_); q += "<="; q.append (v, conversion_); return q; } template query less_equal (val_bind v) const { copy_bind c (v.val); return less_equal (c); } query less_equal (ref_bind r) const { query q (table_, column_); q += "<="; q.append (r, conversion_); return q; } friend query operator<= (const query_column& c, const T& v) { return c.less_equal (v); } friend query operator<= (const T& v, const query_column& c) { return c.greater_equal (v); } friend query operator<= (const query_column& c, val_bind v) { return c.less_equal (v); } friend query operator<= (val_bind v, const query_column& c) { return c.greater_equal (v); } template friend query operator<= (const query_column& c, val_bind v) { return c.less_equal (v); } template friend query operator<= (val_bind v, const query_column& c) { return c.greater_equal (v); } friend query operator<= (const query_column& c, ref_bind r) { return c.less_equal (r); } friend query operator<= (ref_bind r, const query_column& c) { return c.greater_equal (r); } // >= // public: query greater_equal (const T& v) const { return greater_equal (val_bind (v)); } query greater_equal (val_bind v) const { query q (table_, column_); q += ">="; q.append (v, conversion_); return q; } template query greater_equal (val_bind v) const { copy_bind c (v.val); return greater_equal (c); } query greater_equal (ref_bind r) const { query q (table_, column_); q += ">="; q.append (r, conversion_); return q; } friend query operator>= (const query_column& c, const T& v) { return c.greater_equal (v); } friend query operator>= (const T& v, const query_column& c) { return c.less_equal (v); } friend query operator>= (const query_column& c, val_bind v) { return c.greater_equal (v); } friend query operator>= (val_bind v, const query_column& c) { return c.less_equal (v); } template friend query operator>= (const query_column& c, val_bind v) { return c.greater_equal (v); } template friend query operator>= (val_bind v, const query_column& c) { return c.less_equal (v); } friend query operator>= (const query_column& c, ref_bind r) { return c.greater_equal (r); } friend query operator>= (ref_bind r, const query_column& c) { return c.less_equal (r); } // Column comparison. // public: template query operator== (const query_column& c) const { // We can compare columns only if we can compare their C++ types. // (void) (sizeof (type_instance () == type_instance ())); query q (table_, column_); q += "="; q.append (c.table (), c.column ()); return q; } template query operator!= (const query_column& c) const { // We can compare columns only if we can compare their C++ types. // (void) (sizeof (type_instance () != type_instance ())); query q (table_, column_); q += "!="; q.append (c.table (), c.column ()); return q; } template query operator< (const query_column& c) const { // We can compare columns only if we can compare their C++ types. // (void) (sizeof (type_instance () < type_instance ())); query q (table_, column_); q += "<"; q.append (c.table (), c.column ()); return q; } template query operator> (const query_column& c) const { // We can compare columns only if we can compare their C++ types. // (void) (sizeof (type_instance () > type_instance ())); query q (table_, column_); q += ">"; q.append (c.table (), c.column ()); return q; } template query operator<= (const query_column& c) const { // We can compare columns only if we can compare their C++ types. // (void) (sizeof (type_instance () <= type_instance ())); query q (table_, column_); q += "<="; q.append (c.table (), c.column ()); return q; } template query operator>= (const query_column& c) const { // We can compare columns only if we can compare their C++ types. // (void) (sizeof (type_instance () >= type_instance ())); query q (table_, column_); q += ">="; q.append (c.table (), c.column ()); return q; } private: const char* table_; const char* column_; const char* conversion_; }; // Provide operator+() for using columns to construct native // query fragments (e.g., ORDER BY). // template inline query operator+ (const query_column& c, const std::string& s) { query q (c.table (), c.column ()); q += s; return q; } template inline query operator+ (const std::string& s, const query_column& c) { query q (s); q.append (c.table (), c.column ()); return q; } template inline query operator+ (const query_column& c, const query& q) { query r (c.table (), c.column ()); r += q; return r; } template inline query operator+ (const query& q, const query_column& c) { query r (q); r.append (c.table (), c.column ()); return r; } // // template struct query_param_impl; // BOOLEAN // template struct query_param_impl: query_param { query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool init () { init (*static_cast (value_)); return false; } virtual void bind (bind_type* b) { b->type = bind::boolean; b->buffer = &image_; } virtual unsigned int oid () const { return bool_oid; } private: void init (const T& v) { bool dummy; value_traits::set_image (image_, dummy, v); } private: bool image_; }; // SMALLINT // template struct query_param_impl: query_param { query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool init () { init (*static_cast (value_)); return false; } virtual void bind (bind_type* b) { b->type = bind::smallint; b->buffer = &image_; } virtual unsigned int oid () const { return int2_oid; } private: void init (const T& v) { bool dummy; value_traits::set_image (image_, dummy, v); } private: short image_; }; // INTEGER // template struct query_param_impl: query_param { query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool init () { init (*static_cast (value_)); return false; } virtual void bind (bind_type* b) { b->type = bind::integer; b->buffer = &image_; } virtual unsigned int oid () const { return int4_oid; } private: void init (const T& v) { bool dummy; value_traits::set_image (image_, dummy, v); } private: int image_; }; // BIGINT // template struct query_param_impl: query_param { query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool init () { init (*static_cast (value_)); return false; } virtual void bind (bind_type* b) { b->type = bind::bigint; b->buffer = &image_; } virtual unsigned int oid () const { return int8_oid; } private: void init (const T& v) { bool dummy; value_traits::set_image (image_, dummy, v); } private: long long image_; }; // REAL // template struct query_param_impl: query_param { query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool init () { init (*static_cast (value_)); return false; } virtual void bind (bind_type* b) { b->type = bind::real; b->buffer = &image_; } virtual unsigned int oid () const { return float4_oid; } private: void init (const T& v) { bool dummy; value_traits::set_image (image_, dummy, v); } private: float image_; }; // DOUBLE // template struct query_param_impl: query_param { query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool init () { init (*static_cast (value_)); return false; } virtual void bind (bind_type* b) { b->type = bind::double_; b->buffer = &image_; } virtual unsigned int oid () const { return float8_oid; } private: void init (const T& v) { bool dummy; value_traits::set_image (image_, dummy, v); } private: double image_; }; // NUMERIC // template struct query_param_impl: query_param { query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool init () { return init (*static_cast (value_)); } virtual void bind (bind_type* b) { b->type = bind::numeric; b->buffer = buffer_.data (); b->capacity = buffer_.capacity (); b->size = &size_; } virtual unsigned int oid () const { return numeric_oid; } private: bool init (const T& v) { bool dummy; std::size_t size (0), cap (buffer_.capacity ()); value_traits::set_image (buffer_, size, dummy, v); size_ = size; return cap != buffer_.capacity (); } private: details::buffer buffer_; std::size_t size_; }; // DATE // template struct query_param_impl: query_param { query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool init () { init (*static_cast (value_)); return false; } virtual void bind (bind_type* b) { b->type = bind::date; b->buffer = &image_; } virtual unsigned int oid () const { return date_oid; } private: void init (const T& v) { bool dummy; value_traits::set_image (image_, dummy, v); } private: int image_; }; // TIME // template struct query_param_impl: query_param { query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool init () { init (*static_cast (value_)); return false; } virtual void bind (bind_type* b) { b->type = bind::time; b->buffer = &image_; } virtual unsigned int oid () const { return time_oid; } private: void init (const T& v) { bool dummy; value_traits::set_image (image_, dummy, v); } private: long long image_; }; // TIMESTAMP // template struct query_param_impl: query_param { query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool init () { init (*static_cast (value_)); return false; } virtual void bind (bind_type* b) { b->type = bind::timestamp; b->buffer = &image_; } virtual unsigned int oid () const { return timestamp_oid; } private: void init (const T& v) { bool dummy; value_traits::set_image (image_, dummy, v); } private: long long image_; }; // STRING // template struct query_param_impl: query_param { query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool init () { return init (*static_cast (value_)); } virtual void bind (bind_type* b) { b->type = bind::text; b->buffer = buffer_.data (); b->capacity = buffer_.capacity (); b->size = &size_; } virtual unsigned int oid () const { return text_oid; } private: bool init (const T& v) { bool dummy; std::size_t size (0), cap (buffer_.capacity ()); value_traits::set_image (buffer_, size, dummy, v); size_ = size; return cap != buffer_.capacity (); } private: details::buffer buffer_; std::size_t size_; }; // BYTEA // template struct query_param_impl: query_param { query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool init () { return init (*static_cast (value_)); } virtual void bind (bind_type* b) { b->type = bind::bytea; b->buffer = buffer_.data (); b->capacity = buffer_.capacity (); b->size = &size_; } virtual unsigned int oid () const { return bytea_oid; } private: bool init (const T& v) { bool dummy; std::size_t size (0), cap (buffer_.capacity ()); value_traits::set_image (buffer_, size, dummy, v); size_ = size; return cap != buffer_.capacity (); } private: details::buffer buffer_; std::size_t size_; }; // BIT // template struct query_param_impl: query_param { query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool init () { return init (*static_cast (value_)); } virtual void bind (bind_type* b) { b->type = bind::bit; b->buffer = buffer_.data (); b->capacity = buffer_.capacity (); b->size = &size_; } private: bool init (const T& v) { bool dummy; std::size_t size (0), cap (buffer_.capacity ()); // NOTE: Using a fixed size bit type in queries requires // alternative image buffer type support. // value_traits::set_image (buffer_, size, dummy, v); size_ = size; return cap != buffer_.capacity (); } private: details::ubuffer buffer_; std::size_t size_; }; // VARBIT // template struct query_param_impl: query_param { query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool init () { return init (*static_cast (value_)); } virtual void bind (bind_type* b) { b->type = bind::varbit; b->buffer = buffer_.data (); b->capacity = buffer_.capacity (); b->size = &size_; } virtual unsigned int oid () const { return varbit_oid; } private: bool init (const T& v) { bool dummy; std::size_t size (0), cap (buffer_.capacity ()); value_traits::set_image (buffer_, size, dummy, v); size_ = size; return cap != buffer_.capacity (); } private: details::ubuffer buffer_; std::size_t size_; }; // UUID // template struct query_param_impl: query_param { query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} virtual bool init () { init (*static_cast (value_)); return false; } virtual void bind (bind_type* b) { b->type = bind::uuid; b->buffer = buffer_; } virtual unsigned int oid () const { return uuid_oid; } private: void init (const T& v) { bool dummy; value_traits::set_image (buffer_, dummy, v); } private: unsigned char buffer_[16]; }; } } // odb::query specialization for PostgreSQL. // namespace odb { template class query: public pgsql::query, public query_selector::columns_type { public: // We don't define any typedefs here since they may clash with // column names defined by our base type. // query () { } explicit query (bool v) : pgsql::query (v) { } explicit query (const char* q) : pgsql::query (q) { } explicit query (const std::string& q) : pgsql::query (q) { } template explicit query (pgsql::val_bind v) : pgsql::query (pgsql::query (v)) { } template explicit query (pgsql::ref_bind r) : pgsql::query (pgsql::query (r)) { } query (const pgsql::query& q) : pgsql::query (q) { } template query (const pgsql::query_column& qc) : pgsql::query (qc) { } }; } #include #include #include #endif // ODB_PGSQL_QUERY_HXX