MySQL++

Artifact [45a3d9569e]
Login

Artifact 45a3d9569eea39511ffb851e16dc42d2c2e19ccc800d49659cb2511bb77f6cad:


     1  /// \file result.h
     2  /// \brief Declares classes for holding information about SQL query
     3  /// results.
     4  
     5  /***********************************************************************
     6   Copyright (c) 1998 by Kevin Atkinson, (c) 1999-2001 by MySQL AB, and
     7   (c) 2004-2007 by Educational Technology Resources, Inc.  Others may
     8   also hold copyrights on code in this file.  See the CREDITS.txt file
     9   in the top directory of the distribution for details.
    10  
    11   This file is part of MySQL++.
    12  
    13   MySQL++ is free software; you can redistribute it and/or modify it
    14   under the terms of the GNU Lesser General Public License as published
    15   by the Free Software Foundation; either version 2.1 of the License, or
    16   (at your option) any later version.
    17  
    18   MySQL++ is distributed in the hope that it will be useful, but WITHOUT
    19   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    20   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
    21   License for more details.
    22  
    23   You should have received a copy of the GNU Lesser General Public
    24   License along with MySQL++; if not, write to the Free Software
    25   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
    26   USA
    27  ***********************************************************************/
    28  
    29  #if !defined(MYSQLPP_RESULT_H)
    30  #define MYSQLPP_RESULT_H
    31  
    32  #include "common.h"
    33  
    34  #include "exceptions.h"
    35  #include "field.h"
    36  #include "field_names.h"
    37  #include "field_types.h"
    38  #include "noexceptions.h"
    39  #include "refcounted.h"
    40  #include "row.h"
    41  
    42  namespace mysqlpp {
    43  
    44  
    45  /// \brief Holds information about the result of queries that don't
    46  /// return rows.
    47  
    48  class MYSQLPP_EXPORT SimpleResult
    49  {
    50  private:
51 /// \brief Pointer to bool data member, for use by safe bool 52 /// conversion operator. 53 /// 54 /// \see http://www.artima.com/cppsource/safebool.html 55 typedef bool SimpleResult::*private_bool_type;
56 57 public: 58 /// \brief Default ctor 59 SimpleResult() : 60 copacetic_(false), 61 insert_id_(0), 62 rows_(0) 63 { 64 } 65 66 /// \brief Initialize object 67 SimpleResult(bool copacetic, ulonglong insert_id, 68 ulonglong rows, const std::string& info) : 69 copacetic_(copacetic), 70 insert_id_(insert_id), 71 rows_(rows), 72 info_(info) 73 { 74 } 75 76 /// \brief Test whether the query that created this result succeeded 77 /// 78 /// If you test this object in bool context and it's false, it's a 79 /// signal that the query this was created from failed in some way. 80 /// Call Query::error() or Query::errnum() to find out what exactly 81 /// happened. 82 operator private_bool_type() const 83 { 84 return copacetic_ ? &SimpleResult::copacetic_ : 0; 85 } 86 87 /// \brief Get the last value used for an AUTO_INCREMENT field 88 ulonglong insert_id() const { return insert_id_; } 89 90 /// \brief Get the number of rows affected by the query 91 ulonglong rows() const { return rows_; } 92 93 /// \brief Get any additional information about the query returned 94 /// by the server. 95 const char* info() const { return info_.c_str(); } 96 97 private: 98 bool copacetic_; 99 ulonglong insert_id_; 100 ulonglong rows_; 101 std::string info_; 102 }; 103 104 105 /// \brief Base class for StoreQueryResult and UseQueryResult. 106 /// 107 /// Not useful directly. Just contains common functionality for its 108 /// subclasses. 109 110 class MYSQLPP_EXPORT ResultBase : public OptionalExceptions 111 { 112 public: 113 /// \brief Destroy object 114 virtual ~ResultBase() { } 115 116 /// \brief Returns the next field in this result set 117 const Field& fetch_field() const 118 { return fields_.at(current_field_++); } 119 120 /// \brief Returns the given field in this result set 121 const Field& fetch_field(Fields::size_type i) const 122 { return fields_.at(i); } 123 124 /// \brief Get the underlying Field structure given its index. 125 const Field& field(unsigned int i) const { return fields_.at(i); } 126 127 /// \brief Get the underlying Fields structure. 128 const Fields& fields() const { return fields_; } 129 130 /// \brief Get the name of the field at the given index. 131 const std::string& field_name(int i) const 132 { return names_->at(i); } 133 134 /// \brief Get the names of the fields within this result set. 135 const RefCountedPointer<FieldNames>& field_names() const 136 { return names_; } 137 138 /// \brief Get the index of the named field. 139 /// 140 /// This is the inverse of field_name(). 141 int field_num(const std::string&) const; 142 143 /// \brief Get the type of a particular field within this result set. 144 const FieldTypes::value_type& field_type(int i) const 145 { return types_->at(i); } 146 147 /// \brief Get a list of the types of the fields within this 148 /// result set. 149 const RefCountedPointer<FieldTypes>& field_types() const 150 { return types_; } 151 152 /// \brief Returns the number of fields in this result set 153 size_t num_fields() const { return fields_.size(); } 154 155 /// \brief Return the name of the table the result set comes from 156 const char* table() const 157 { return fields_.empty() ? "" : fields_[0].table(); } 158 159 protected: 160 /// \brief Create empty object 161 ResultBase() : 162 driver_(0), 163 current_field_(0) 164 { 165 } 166 167 /// \brief Create the object, fully initialized 168 ResultBase(MYSQL_RES* result, DBDriver* dbd, bool te = true); 169 170 /// \brief Create object as a copy of another ResultBase 171 ResultBase(const ResultBase& other) : 172 OptionalExceptions() 173 { 174 copy(other); 175 } 176 177 /// \brief Copy another ResultBase object's contents into this one. 178 ResultBase& copy(const ResultBase& other); 179 180 DBDriver* driver_; ///< Access to DB driver; fully initted if nonzero 181 Fields fields_; ///< list of fields in result 182 183 /// \brief list of field names in result 184 RefCountedPointer<FieldNames> names_; 185 186 /// \brief list of field types in result 187 RefCountedPointer<FieldTypes> types_; 188 189 /// \brief Default field index used by fetch_field() 190 /// 191 /// It's mutable because it's just internal housekeeping: it's 192 /// changed by fetch_field(void), but it doesn't change the "value" 193 /// of the result. See mutability justification for 194 /// UseQueryResult::result_: this field provides functionality we 195 /// used to get through result_, so it's relevant here, too. 196 mutable Fields::size_type current_field_; 197 }; 198 199 200 /// \brief StoreQueryResult set type for "store" queries 201 /// 202 /// This is the obvious C++ implementation of a class to hold results 203 /// from a SQL query that returns rows: a specialization of std::vector 204 /// holding Row objects in memory so you get random-access semantics. 205 /// MySQL++ also supports UseQueryResult which is less friendly, but has 206 /// better memory performance. See the user manual for more details on 207 /// the distinction and the usage patterns required. 208 209 class MYSQLPP_EXPORT StoreQueryResult : 210 public ResultBase, 211 public std::vector<Row> 212 { 213 private: 214 /// \brief Pointer to bool data member, for use by safe bool 215 /// conversion operator. 216 /// 217 /// \see http://www.artima.com/cppsource/safebool.html 218 typedef bool StoreQueryResult::*private_bool_type; 219 220 public: 221 typedef std::vector<Row> list_type; ///< type of vector base class 222 223 /// \brief Default constructor 224 StoreQueryResult() : 225 ResultBase(), 226 copacetic_(false) 227 { 228 } 229 230 /// \brief Fully initialize object 231 StoreQueryResult(MYSQL_RES* result, DBDriver* dbd, bool te = true); 232 233 /// \brief Initialize object as a copy of another StoreQueryResult 234 /// object 235 StoreQueryResult(const StoreQueryResult& other) : 236 ResultBase(), 237 std::vector<Row>(), 238 copacetic_(false) 239 { 240 copy(other); 241 } 242 243 /// \brief Destroy result set 244 ~StoreQueryResult() { } 245 246 /// \brief Returns the number of rows in this result set 247 list_type::size_type num_rows() const { return size(); } 248 249 /// \brief Copy another StoreQueryResult object's data into this 250 /// object 251 StoreQueryResult& operator =(const StoreQueryResult& rhs) 252 { return this != &rhs ? copy(rhs) : *this; } 253 254 /// \brief Test whether the query that created this result succeeded 255 /// 256 /// If you test this object in bool context and it's false, it's a 257 /// signal that the query this was created from failed in some way. 258 /// Call Query::error() or Query::errnum() to find out what exactly 259 /// happened. 260 operator private_bool_type() const 261 { 262 return copacetic_ ? &StoreQueryResult::copacetic_ : 0; 263 } 264 265 private: 266 /// \brief Copy another StoreQueryResult object's contents into this 267 /// one. 268 StoreQueryResult& copy(const StoreQueryResult& other); 269 270 bool copacetic_; ///< true if initialized from a good result set 271 }; 272 273 274 /// \brief Functor to call mysql_free_result() on the pointer you pass 275 /// to it. 276 /// 277 /// This overrides RefCountedPointer's default destroyer, which uses 278 /// operator delete; it annoys the C API when you nuke its data 279 /// structures this way. :) 280 template <> 281 struct RefCountedPointerDestroyer<MYSQL_RES> 282 { 283 /// \brief Functor implementation 284 void operator()(MYSQL_RES* doomed) const 285 { 286 if (doomed) { 287 mysql_free_result(doomed); 288 } 289 } 290 }; 291 292 293 /// \brief StoreQueryResult set type for "use" queries 294 /// 295 /// See the user manual for the reason you might want to use this even 296 /// though its interface is less friendly than StoreQueryResult's. 297 298 class MYSQLPP_EXPORT UseQueryResult : public ResultBase 299 { 300 public: 301 /// \brief Default constructor 302 UseQueryResult() : 303 ResultBase() 304 { 305 } 306 307 /// \brief Create the object, fully initialized 308 UseQueryResult(MYSQL_RES* result, DBDriver* dbd, bool te = true); 309 310 /// \brief Create a copy of another UseQueryResult object 311 UseQueryResult(const UseQueryResult& other) : 312 ResultBase() 313 { 314 copy(other); 315 } 316 317 /// \brief Destroy object 318 ~UseQueryResult() { } 319 320 /// \brief Copy another UseQueryResult object's data into this object 321 UseQueryResult& operator =(const UseQueryResult& rhs) 322 { return this != &rhs ? copy(rhs) : *this; } 323 324 /// \brief Returns the next field in this result set 325 const Field& fetch_field() const 326 { return fields_.at(current_field_++); } 327 328 /// \brief Returns the given field in this result set 329 const Field& fetch_field(Fields::size_type i) const 330 { return fields_.at(i); } 331 332 /// \brief Returns the lengths of the fields in the current row of 333 /// the result set. 334 /// 335 /// \internal This should not be terribly useful to end-user code. 336 /// The Row object returned by fetch_row() contains these lengths. 337 const unsigned long* fetch_lengths() const; 338 339 /// \brief Returns the next row in a "use" query's result set 340 /// 341 /// This is a thick wrapper around DBDriver::fetch_row(). It does a 342 /// lot of error checking before returning the Row object containing 343 /// the row data. 344 /// 345 /// \sa fetch_raw_row() 346 Row fetch_row() const; 347 348 /// \brief Wraps mysql_fetch_row() in MySQL C API. 349 /// 350 /// \internal You almost certainly want to call fetch_row() instead. 351 /// It is anticipated that this is only useful within the library, 352 /// to implement higher-level query types on top of raw "use" 353 /// queries. Query::storein() uses it, for example. 354 MYSQL_ROW fetch_raw_row() const; 355 356 /// \brief Jumps to the given field within the result set 357 /// 358 /// Calling this allows you to reset the default field index used 359 /// by fetch_field(). 360 void field_seek(Fields::size_type field) const 361 { current_field_ = field; } 362 363 /// \brief Return the pointer to the underlying MySQL C API 364 /// result set object. 365 /// 366 /// While this has obvious inherent value for those times you need 367 /// to dig beneath the MySQL++ interface, it has subtler value. 368 /// It effectively stands in for operator bool(), operator !(), 369 /// operator ==(), and operator !=(), because the C++ compiler can 370 /// implement all of these with a MYSQL_RES*. 371 /// 372 /// Of these uses, the most valuable is using the UseQueryResult 373 /// object in bool context to determine if the query that created 374 // it was successful: 375 /// 376 /// \code 377 /// Query q("...."); 378 /// if (UseQueryResult res = q.use()) { 379 /// // Can use 'res', query succeeded 380 /// } 381 /// else { 382 /// // Query failed, call Query::error() or ::errnum() for why 383 /// } 384 /// \endcode 385 operator MYSQL_RES*() const { return result_.raw(); } 386 387 private: 388 /// \brief Copy another ResultBase object's contents into this one. 389 UseQueryResult& copy(const UseQueryResult& other); 390 391 /// \brief Reference to underlying C API result set 392 /// 393 /// This is mutable because so many methods in this class are 394 /// are justifiably const because they don't modify the result 395 /// set's "value" but they call C API methods that take non-const 396 /// MYSQL_RES* so they can only be const if this is mutable. It's 397 /// quite likely that these API functions do modify the MYSQL_RES 398 /// object, so strict constness says this object changed, too, but 399 /// this has always been mutable and the resulting behavior hasn't 400 /// confused anyone yet. 401 mutable RefCountedPointer<MYSQL_RES> result_; 402 }; 403 404 405 /// \brief Swaps two StoreQueryResult objects 406 inline void 407 swap(StoreQueryResult& x, StoreQueryResult& y) 408 { 409 StoreQueryResult tmp = x; 410 x = y; 411 y = tmp; 412 } 413 414 /// \brief Swaps two UseQueryResult objects 415 inline void 416 swap(UseQueryResult& x, UseQueryResult& y) 417 { 418 UseQueryResult tmp = x; 419 x = y; 420 y = tmp; 421 } 422 423 } // end namespace mysqlpp 424 425 #endif // !defined(MYSQLPP_RESULT_H)