1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770
|
/// \file mystring.h
/// \brief Declares String class, MySQL++'s generic std::string-like
/// class, used for holding data received from the database server.
/***********************************************************************
Copyright (c) 1998 by Kevin Atkinson, (c) 1999-2001 by MySQL AB, and
(c) 2004-2008 by Educational Technology Resources, Inc. Others may
also hold copyrights on code in this file. See the CREDITS.txt file
in the top directory of the distribution for details.
This file is part of MySQL++.
MySQL++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
MySQL++ is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public
License along with MySQL++; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
USA
***********************************************************************/
#if !defined(MYSQLPP_MYSTRING_H)
#define MYSQLPP_MYSTRING_H
#include "common.h"
#include "datetime.h"
#include "exceptions.h"
#include "null.h"
#include "sql_buffer.h"
#include <string>
#include <sstream>
#include <limits>
#include <stdlib.h>
#include <string.h>
namespace mysqlpp {
#if !defined(DOXYGEN_IGNORE)
// Doxygen will not generate documentation for this section.
namespace detail
{
template<typename T, bool is_signed = std::numeric_limits<T>::is_signed>
struct conv_promotion;
template<>
struct conv_promotion<float>
{
typedef double type;
};
template<>
struct conv_promotion<double>
{
typedef double type;
};
# if !defined(NO_LONG_LONGS)
template<>
struct conv_promotion<unsigned long long>
{
typedef unsigned long long type;
};
template<>
struct conv_promotion<long long>
{
typedef long long type;
};
# endif
// preserve existing behaviour, char converted as signed long
template<>
struct conv_promotion<char>
{
typedef long type;
};
// all other types use signed/unsigned long
template<typename T>
struct conv_promotion<T, true>
{
typedef long type;
};
template<typename T>
struct conv_promotion<T, false>
{
typedef unsigned long type;
};
} // namespace detail
class MYSQLPP_EXPORT SQLTypeAdapter;
#endif // !defined(DOXYGEN_IGNORE)
/// \brief A std::string work-alike that can convert itself from SQL
/// text data formats to C++ data types.
///
/// This class is an intermediate form for a SQL field, normally
/// converted to a more useful native C++ type, not used directly.
/// The only exception is in dealing with BLOB data, which stays in
/// String form for efficiency and to avoid corrupting the data with
/// facile conversions. Even then, it's best to use it through the
/// typedef aliases like sql_blob in sql_types.h, in case we later
/// change this underlying representation.
///
/// String's implicit conversion operators let you can use these
/// objects naturally:
///
/// \code String("12.86") + 2.0 \endcode
///
/// That will give you 14.86 (approximately) as you expect, but be
/// careful not to get tripped up by C++'s type conversion rules. If
/// you had said this instead:
///
/// \code String("12.86") + 2 \endcode
///
/// the result would be 14 because 2 is an integer, and C++'s type
/// conversion rules put the String object in an integer context.
///
/// You can disable the operator overloads that allow these things by
/// defining MYSQLPP_NO_BINARY_OPERS.
///
/// This class also has some basic information about the type of data
/// stored in it, to allow it to do the conversions more intelligently
/// than a trivial implementation would allow.
class MYSQLPP_EXPORT String
{
public:
/// \brief Type of the data stored in this object, when it is not
/// equal to SQL null.
typedef const char value_type;
/// \brief Type of "size" integers
typedef size_t size_type;
/// \brief Type of iterators
typedef const char* const_iterator;
/// \brief Same as const_iterator because the data cannot be
/// changed.
typedef const_iterator iterator;
#if !defined(DOXYGEN_IGNORE)
// Doxygen will not generate documentation for this section.
typedef int difference_type;
typedef const char* const_pointer;
typedef const_pointer pointer;
#endif // !defined(DOXYGEN_IGNORE)
/// \brief Default constructor
///
/// An object constructed this way is essentially useless, but
/// sometimes you just need to construct a default object.
String() :
buffer_()
{
}
/// \brief Copy ctor
///
/// \param other the other String object
///
/// This ctor only copies the pointer to the other String's data
/// buffer and increments its reference counter. If you need a
/// deep copy, use one of the ctors that takes a string.
String(const String& other) :
buffer_(other.buffer_)
{
}
/// \brief Full constructor.
///
/// \param str the string this object represents, or 0 for SQL null
/// \param len the length of the string; embedded nulls are legal
/// \param type MySQL type information for data within str
/// \param is_null string represents a SQL null, not literal data
///
/// The resulting object will contain a copy of the string buffer.
/// The buffer will actually be 1 byte longer than the value given
/// for \c len, to hold a null terminator for safety. We do this
/// because this ctor may be used for things other than
/// null-terminated C strings. (e.g. BLOB data)
explicit String(const char* str, size_type len,
mysql_type_info type = mysql_type_info::string_type,
bool is_null = false) :
buffer_(new SQLBuffer(str, len, type, is_null))
{
}
/// \brief C++ string version of full ctor
///
/// \param str the string this object represents, or 0 for SQL null
/// \param type MySQL type information for data within str
/// \param is_null string represents a SQL null, not literal data
///
/// The resulting object will contain a copy of the string buffer.
explicit String(const std::string& str,
mysql_type_info type = mysql_type_info::string_type,
bool is_null = false) :
buffer_(new SQLBuffer(str.data(), static_cast<size_type>(str.length()),
type, is_null))
{
}
/// \brief Null-terminated C string version of full ctor
///
/// \param str the string this object represents, or 0 for SQL null
/// \param type MySQL type information for data within str
/// \param is_null string represents a SQL null, not literal data
///
/// The resulting object will contain a copy of the string buffer.
explicit String(const char* str,
mysql_type_info type = mysql_type_info::string_type,
bool is_null = false) :
buffer_(new SQLBuffer(str, static_cast<size_type>(strlen(str)),
type, is_null))
{
}
/// \brief Destroy string
~String() { }
/// \brief Assign raw data to this object
///
/// This parallels the ctor with the same parameters, for when you
/// must do a 2-step create, or when you want to reassign the data
/// without creating a String temporary to get around the fact
/// that operator=() can only take one parameter.
void assign(const char* str, size_type len,
mysql_type_info type = mysql_type_info::string_type,
bool is_null = false)
{
buffer_ = new SQLBuffer(str, len, type, is_null);
}
/// \brief Assign a C++ string to this object
///
/// This parallels the ctor with the same parameters, for when you
/// must do a 2-step create, or when you want to reassign the data
/// without creating a String temporary to get around the fact
/// that operator=() can only take one parameter.
void assign(const std::string& str,
mysql_type_info type = mysql_type_info::string_type,
bool is_null = false)
{
buffer_ = new SQLBuffer(str.data(),
static_cast<size_type>(str.length()), type, is_null);
}
/// \brief Assign a C string to this object
///
/// This parallels the ctor with the same parameters, for when you
/// must do a 2-step create, or when you want to reassign the data
/// without creating a String temporary to get around the fact
/// that operator=() can only take one parameter.
void assign(const char* str,
mysql_type_info type = mysql_type_info::string_type,
bool is_null = false)
{
buffer_ = new SQLBuffer(str, static_cast<size_type>(strlen(str)),
type, is_null);
}
/// \brief Return a character within the string.
///
/// \throw mysqlpp::BadIndex if the row is not initialized or there
/// are less than \c i fields in the row.
char at(size_type pos) const;
/// \brief Return iterator pointing to the first character of
/// the string
const_iterator begin() const { return data(); }
/// \brief Return a const pointer to the string data.
const char* c_str() const { return data(); }
#if defined(MYSQLPP_PLATFORM_VISUAL_CPP)
// Squish VC++ warning about "possible loss of data" for these conversions
# pragma warning(disable: 4244)
#endif
/// \brief Template for converting the column data to most any
/// numeric data type.
template <class Type>
Type conv(Type) const
{
// Conversions are done using one of double/long/ulong/llong/ullong
// so we call a helper function to do the work using that type.
// This reduces the amount of template code instantiated.
typedef typename detail::conv_promotion<Type>::type conv_type;
return do_conv<conv_type>(typeid(Type).name());
}
#if defined(MYSQLPP_PLATFORM_VISUAL_CPP)
# pragma warning(default: 4244)
#endif
/// \brief Overload of conv() for types wrapped with Null<>
///
/// If the String object was initialized with some string we
/// recognize as a SQL null, we just return a copy of the global
/// 'null' object converted to the requested type. Otherwise, we
/// return the String's value wrapped in the Null<> template.
template <class T, class B>
Null<T, B> conv(Null<T, B>) const
{
if (is_null()) {
return Null<T, B>(null);
}
else {
return Null<T, B>(conv(T()));
}
}
/// \brief Lexically compare this string to another.
///
/// \param other string to compare against this one
///
/// \see compare(size_type, size_type, const char*)
int compare(const String& other) const;
/// \brief Lexically compare this string to another.
///
/// \param other string to compare against this one
///
/// \see compare(size_type, size_type, const char*)
int compare(const std::string& other) const;
/// \brief Lexically compare this string to another.
///
/// \param pos position within this string to begin comparison
/// \param num maximum number of characters within this string to
/// use in comparison
/// \param other string to compare against this one
///
/// \see compare(size_type, size_type, const char*)
int compare(size_type pos, size_type num, std::string& other) const;
/// \brief Lexically compare this string to another.
///
/// \param other string to compare against this one
///
/// \see compare(size_type, size_type, const char*)
int compare(const char* other) const;
/// \brief Lexically compare this string to another.
///
/// \param pos position within this string to begin comparison
/// \param num maximum number of characters within this string to
/// use in comparison
/// \param other string to compare against this one
///
/// \retval < 0 if this string is lexically "less than" other
/// \retval 0 if this string is equal to other
/// \retval > 0 if this string is lexically "greater than" other
int compare(size_type pos, size_type num, const char* other) const;
/// \brief Raw access to the underlying buffer, with no C string
/// interpretation.
const char* data() const;
/// \brief Returns true if size() == 0
bool empty() const { return size() == 0; }
/// \brief Return iterator pointing to one past the last character
/// of the string.
const_iterator end() const;
/// \brief Returns true if data of this type should be escaped, false
/// otherwise.
bool escape_q() const;
/// \brief Returns true if this object is a SQL null.
bool is_null() const;
/// \brief Set a flag indicating that this object is a SQL null.
void it_is_null();
/// \brief Return number of bytes in the string
///
/// Note that this doesn't count the number of \b characters in the
/// string. If your database is configured to use an 8-bit character
/// set, this is a distinction without a difference. But, if you're
/// using UTF-8 in the database, you will need to "widen" the UTF-8
/// data to use a fixed-size character set like UCS-2 and count the
/// characters that way. You might use std::wstring, for example.
size_type length() const;
/// \brief Return the maximum number of characters in the string.
///
/// Because this is a \c const string, this is just an alias for
/// size(); its size is always equal to the amount of data currently
/// stored.
size_type max_size() const { return size(); }
/// \brief Returns true if data of this type should be quoted, false
/// otherwise.
bool quote_q() const;
/// \brief Return number of bytes in string
///
/// See commentary for length() about the difference between bytes
/// and characters.
size_type size() const { return length(); }
/// \brief Returns a copy of our internal string without leading
/// blanks.
void strip_leading_blanks(std::string& s) const
{
const char* pc = data();
if (pc) {
size_type n = length();
while (n && (*pc == ' ')) {
++pc;
--n;
}
s.assign(pc, n);
}
else {
s.clear();
}
}
/// \brief Copies this object's data into a C++ string.
///
/// If you know the data doesn't contain null characters (i.e. it's
/// a typical string, not BLOB data), it's more efficient to just
/// assign this object to anything taking \c const \c char*. (Or
/// equivalently, call the \c data() method.) This copies a pointer
/// to a buffer instead of copying the buffer's contents.
void to_string(std::string& s) const;
/// \brief Get this object's current MySQL type.
mysql_type_info type() const
{
return buffer_ ? buffer_->type() : mysql_type_info::string_type;
}
/// \brief Assignment operator, from C++ string
String& operator =(const std::string& rhs)
{
buffer_ = new SQLBuffer(rhs.data(),
static_cast<size_type>(rhs.length()),
mysql_type_info::string_type, false);
return *this;
}
/// \brief Assignment operator, from C string
///
/// This creates a copy of the entire string, not just a copy of
/// the pointer.
String& operator =(const char* str)
{
buffer_ = new SQLBuffer(str,
static_cast<size_type>(strlen(str)),
mysql_type_info::string_type, false);
return *this;
}
/// \brief Assignment operator, from other String
///
/// This only copies the pointer to the other String's data
/// buffer and increments its reference counter. If you need a
/// deep copy, assign a string to this object instead.
String& operator =(const String& other)
{
buffer_ = other.buffer_;
return *this;
}
/// \brief Equality comparison operator
///
/// For comparing this object to any of the data types we have a
/// compare() overload for.
template <typename T>
bool operator ==(const T& rhs) const
{
return compare(rhs) == 0;
}
/// \brief Equality comparison operator
///
/// For checking object against MySQL++'s global \c null constant
bool operator ==(const mysqlpp::null_type&) const
{
return is_null();
}
/// \brief Inequality comparison operator
///
/// For comparing this object to any of the data types we have a
/// compare() overload for.
template <typename T>
bool operator !=(const T& rhs) const
{
return compare(rhs) != 0;
}
/// \brief Inequality comparison operator
///
/// For checking object against MySQL++'s global \c null constant
bool operator !=(const mysqlpp::null_type&) const
{
return !is_null();
}
/// \brief Return a character within the string.
///
/// This function is just syntactic sugar, wrapping the at() method.
///
/// \throw mysqlpp::BadIndex if the string is not initialized or there
/// are less than \c i fields in the string.
char operator [](size_type pos) const { return at(pos); }
/// \brief Returns a const char pointer to the object's raw data
operator const char*() const { return data(); }
/// \brief Converts this object's string data to a signed char
operator signed char() const
{ return conv(static_cast<signed char>(0)); }
/// \brief Converts this object's string data to an unsigned char
operator unsigned char() const
{ return conv(static_cast<unsigned char>(0)); }
/// \brief Converts this object's string data to an int
operator int() const
{ return conv(static_cast<int>(0)); }
/// \brief Converts this object's string data to an unsigned int
operator unsigned int() const
{ return conv(static_cast<unsigned int>(0)); }
/// \brief Converts this object's string data to a short int
operator short int() const
{ return conv(static_cast<short int>(0)); }
/// \brief Converts this object's string data to an unsigned short
/// int
operator unsigned short int() const
{ return conv(static_cast<unsigned short int>(0)); }
/// \brief Converts this object's string data to a long int
operator long int() const
{ return conv(static_cast<long int>(0)); }
/// \brief Converts this object's string data to an unsigned long
/// int
operator unsigned long int() const
{ return conv(static_cast<unsigned long int>(0)); }
#if !defined(NO_LONG_LONGS)
/// \brief Converts this object's string data to the platform-
/// specific 'longlong' type, usually a 64-bit integer.
operator longlong() const
{ return conv(static_cast<longlong>(0)); }
/// \brief Converts this object's string data to the platform-
/// specific 'ulonglong' type, usually a 64-bit unsigned integer.
operator ulonglong() const
{ return conv(static_cast<ulonglong>(0)); }
#endif
/// \brief Converts this object's string data to a float
operator float() const
{ return conv(static_cast<float>(0)); }
/// \brief Converts this object's string data to a double
operator double() const
{ return conv(static_cast<double>(0)); }
/// \brief Converts this object's string data to a bool
operator bool() const { return buffer_ ? atoi(c_str()) : false; }
/// \brief Converts this object's string data to a mysqlpp::Date
operator Date() const { return buffer_ ? Date(*this) : Date(); }
/// \brief Converts this object's string data to a mysqlpp::DateTime
operator DateTime() const
{ return buffer_ ? DateTime(*this) : DateTime(); }
/// \brief Converts this object's string data to a mysqlpp::Time
operator Time() const { return buffer_ ? Time(*this) : Time(); }
/// \brief Converts the String to a nullable data type
///
/// This is just an implicit version of conv(Null<T, B>)
template <class T, class B>
operator Null<T, B>() const { return conv(Null<T, B>()); }
private:
/// \brief Do the actual numeric conversion via @p Type.
template <class Type>
Type do_conv(const char* type_name) const
{
if (buffer_) {
std::stringstream buf;
buf.write(data(), static_cast<std::streamsize>(length()));
buf.imbue(std::locale::classic()); // "C" locale
Type num = Type();
if (buf >> num) {
char c;
if (!(buf >> c)) {
// Nothing left in buffer, so conversion complete,
// and thus successful.
return num;
}
if (c == '.' &&
(typeid(Type) != typeid(float)) &&
(typeid(Type) != typeid(double))) {
// Conversion stopped on a decimal point -- locale
// doesn't matter to MySQL -- so only way to succeed
// is if it's an integer and everything following
// the decimal is inconsequential.
c = '0'; // handles '.' at end of string
while (buf >> c && c == '0') /* spin */ ;
if (buf.eof() && c == '0') {
return num; // only zeros after decimal point
}
}
}
else if (buf.eof()) {
return num; // nothing to convert, return default value
}
throw BadConversion(type_name, data(), 0, length());
}
else {
return 0;
}
}
RefCountedBuffer buffer_; ///< reference-counted data buffer
friend class SQLTypeAdapter;
};
MYSQLPP_EXPORT std::ostream& operator <<(std::ostream& o,
const String& in);
#if !defined(MYSQLPP_NO_BINARY_OPERS) && !defined(DOXYGEN_IGNORE)
// Ignore this section is MYSQLPP_NO_BINARY_OPERS is defined, or if this
// section is being parsed by Doxygen. In the latter case, it's ignored
// because Doxygen doesn't understand it correctly, and we can't be
// bothered to explain it to Doxygen.
#define oprsw(opr, other, conv) \
inline other operator opr (String x, other y) \
{ return static_cast<conv>(x) opr y; } \
inline other operator opr (other x, String y) \
{ return x opr static_cast<conv>(y); }
#define operator_binary(other, conv) \
oprsw(+, other, conv) \
oprsw(-, other, conv) \
oprsw(*, other, conv) \
oprsw(/, other, conv)
#define operator_binary_int(other, conv) \
operator_binary(other, conv) \
oprsw(%, other, conv) \
oprsw(&, other, conv) \
oprsw(^, other, conv) \
oprsw(|, other, conv) \
oprsw(<<, other, conv) \
oprsw(>>, other, conv)
// Squish more complaints about possible loss of data
#if defined(MYSQLPP_PLATFORM_VISUAL_CPP)
# pragma warning(disable: 4244)
#endif
operator_binary(float, double)
operator_binary(double, double)
operator_binary_int(char, long int)
operator_binary_int(int, long int)
operator_binary_int(short int, long int)
operator_binary_int(long int, long int)
operator_binary_int(unsigned char, unsigned long int)
operator_binary_int(unsigned int, unsigned long int)
operator_binary_int(unsigned short int, unsigned long int)
operator_binary_int(unsigned long int, unsigned long int)
#if defined(MYSQLPP_PLATFORM_VISUAL_CPP)
# pragma warning(default: 4244)
#endif
#if !defined(NO_LONG_LONGS)
operator_binary_int(longlong, longlong)
operator_binary_int(ulonglong, ulonglong)
#endif // !defined(NO_LONG_LONGS)
#endif // !defined(MYSQLPP_NO_BINARY_OPERS) && !defined(DOXYGEN_IGNORE)
#if !defined(DOXYGEN_IGNORE)
// Doxygen isn't smart enough to recognize these template
// specializations. Maybe it's the MYSQLPP_EXPORT tags?
/// \brief Specialization of String::conv<Type>() for bool
///
/// We can either do it this way, or define "\c strtob()" (string to
/// bool, like \c strtol(), \c strtod()...) so we can use
/// internal_string_to_number_proxy.
template <> MYSQLPP_EXPORT bool String::conv(bool) const;
/// \brief Specialization of String::conv<Type>() for String
///
/// Yes, I hear you crying, "WTF!? Why does String need to be able to
/// convert itself to String?" SSQLSes with BLOB columns, that's why.
///
/// SSQLSes populate their data members from the raw field data by
/// calling row["fieldname"].conv(). The raw field data is stored in a
/// String, and the MySQL++ native BLOB type is String. Since we're
/// dealing with generated code, we need this specialization which hand-
/// written code wouldn't need. Prove the truth of this to yourself by
/// removing this and counting how many pieces examples/cgi_jpeg.cpp
/// breaks into.
template <> MYSQLPP_EXPORT String String::conv(String) const;
/// \brief Specialization of String::conv<Type>() for C++ strings
template <> MYSQLPP_EXPORT std::string String::conv(std::string) const;
/// \brief Specialization of String::conv<Type>() for mysqlpp::Date
///
/// This is necessary because as of MySQL++ v3, Date no longer has an
/// implicit conversion ctor from String, and SSQLS uses conv() instead
/// of the C++ type conversion system anyway.
template <> MYSQLPP_EXPORT Date String::conv(Date) const;
/// \brief Specialization of String::conv<Type>() for mysqlpp::DateTime
///
/// This is necessary because as of MySQL++ v3, DateTime no longer has
/// an implicit conversion ctor from String, and SSQLS uses conv()
/// instead of the C++ type conversion system anyway.
template <> MYSQLPP_EXPORT DateTime String::conv(DateTime) const;
/// \brief Specialization of String::conv<Type>() for mysqlpp::Time
///
/// This is necessary because as of MySQL++ v3, Time no longer has an
/// implicit conversion ctor from String, and SSQLS uses conv() instead
/// of the C++ type conversion system anyway.
template <> MYSQLPP_EXPORT Time String::conv(Time) const;
#endif // !defined(DOXYGEN_IGNORE)
} // end namespace mysqlpp
#endif // !defined(MYSQLPP_MYSTRING_H)
|