On Sat, Feb 04, 2006 at 03:40:29AM -0500, Chris Frey wrote:
> Side note: looks like svn didn't pick up your new custom7.cpp in its diff
> output. It's missing in the patch, but I see traces of it in Makefile.am :-)
Ooops! I forgot to svn-add it, sorry. Here is an updated version of the
patch, that includes custom7.cpp.
-Waba.
Index: lib/datetime.h
===================================================================
--- lib/datetime.h (revision 1163)
+++ lib/datetime.h (working copy)
@@ -31,7 +31,6 @@
#include "defs.h"
-#include "coldata.h"
#include "stream2string.h"
#include "tiny_int.h"
@@ -164,19 +163,12 @@
/// \brief Initialize object from a MySQL date-and-time string
///
/// \sa DateTime(cchar*)
- DateTime(const ColData& str)
+ template<class Str>
+ DateTime(const Str &str)
{
convert(str.c_str());
}
- /// \brief Initialize object from a MySQL date-and-time string
- ///
- /// \sa DateTime(cchar*)
- DateTime(const std::string& str)
- {
- convert(str.c_str());
- }
-
/// \brief Compare this datetime to another.
///
/// Returns < 0 if this datetime is before the other, 0 of they are
@@ -259,16 +251,9 @@
/// \brief Initialize object from a MySQL date string
///
/// \sa Date(cchar*)
- Date(const ColData& str) { convert(str.c_str()); }
-
- /// \brief Initialize object from a MySQL date string
- ///
- /// \sa Date(cchar*)
- Date(const std::string& str)
- {
- convert(str.c_str());
- }
-
+ template<class Str>
+ Date(const Str& str) { convert(str.c_str()); }
+
/// \brief Compare this date to another.
///
/// Returns < 0 if this date is before the other, 0 of they are
@@ -342,16 +327,9 @@
/// \brief Initialize object from a MySQL time string
///
/// \sa Time(cchar*)
- Time(const ColData& str) { convert(str.c_str()); }
+ template<class Str>
+ Time(const Str& str) { convert(str.c_str()); }
- /// \brief Initialize object from a MySQL time string
- ///
- /// \sa Time(cchar*)
- Time(const std::string& str)
- {
- convert(str.c_str());
- }
-
/// \brief Parse a MySQL time string into this object.
MYSQLPP_EXPORT cchar* convert(cchar*);
Index: lib/coldata.h
===================================================================
--- lib/coldata.h (revision 1163)
+++ lib/coldata.h (working copy)
@@ -149,6 +149,9 @@
/// \brief Template for converting data from one type to another.
template <class Type> Type conv(Type dummy) const;
+ template <class T, class B> Null<T, B> conv (Null<T, B>) const
+ { return get_null<T, B> (); }
+
/// \brief Set a flag indicating that this object is a SQL null.
void it_is_null() { null_ = true; }
@@ -161,6 +164,19 @@
return buf_;
}
+ /** \brief Convert to a nullable type.
+ *
+ * You have to explicitely provide the template types to the function,
+ * like this:
+ * <code>
+ * Null<T, B> n (col_data.get_null<T, B> ());
+ * </code>
+ *
+ * Or use conv(), to which you can give a sample of the desired
+ * return type.
+ */
+ template <class T, class B> Null<T, B> get_null () const;
+
/// \brief Returns a const char pointer to the string form of
/// this object's data.
operator cchar*() const { return buf_.c_str(); }
@@ -222,8 +238,19 @@
/// \brief Converts this object's string data to a bool
operator bool() const { return conv(0); }
- template <class T, class B> operator Null<T, B>() const;
-
+ /** \brief Dummy conversion to Null.
+ *
+ * This is meant to be ambiguous to the compiler. Without this trick,
+ * Null would be constructible from the other implicit conversion
+ * operators, and would in the end be counter-intuitive to the user
+ * who would lose the is-null information. This way, constructing a
+ * Null from a ColData implicitely is impossible.
+ *
+ * Use get_null() or conv() explicitely instead.
+ */
+ template<class T, class B> operator Null<T, B> () const
+ { T (1)/1; return get_null<T, B> (); }
+
private:
mysql_type_info type_;
std::string buf_;
@@ -295,13 +322,13 @@
/// the object is exactly equal to "NULL". Else, it constructs an empty
/// object of type T and tries to convert it to Null<T, B>.
template <class Str> template<class T, class B>
-ColData_Tmpl<Str>::operator Null<T, B>() const
+Null<T, B> ColData_Tmpl<Str>::get_null () const
{
if ((Str::size() == 4) &&
- (*this)[0] == 'N' &&
- (*this)[1] == 'U' &&
- (*this)[2] == 'L' &&
- (*this)[3] == 'L') {
+ static_cast<Str>(*this)[0] == 'N' &&
+ static_cast<Str>(*this)[1] == 'U' &&
+ static_cast<Str>(*this)[2] == 'L' &&
+ static_cast<Str>(*this)[3] == 'L') {
return Null<T, B>(null);
}
else {
Index: lib/null.h
===================================================================
--- lib/null.h (revision 1163)
+++ lib/null.h (working copy)
@@ -35,6 +35,7 @@
#include "exceptions.h"
#include <iostream>
+#include <string>
namespace mysqlpp {
@@ -273,6 +274,9 @@
return o << n.data;
}
+/// \brief The correct Null template types for nullable STL strings
+typedef Null<std::string, NullisBlank> NullString;
+
} // end namespace mysqlpp
#endif
Index: lib/datetime.cpp
===================================================================
--- lib/datetime.cpp (revision 1163)
+++ lib/datetime.cpp (working copy)
@@ -40,9 +40,9 @@
{
char fill = os.fill('0');
ios::fmtflags flags = os.setf(ios::right);
- os << setw(4) << d.year << '-'
- << setw(2) << d.month << '-'
- << setw(2) << d.day;
+ os << setw(4) << static_cast<int>(d.year) << '-'
+ << setw(2) << static_cast<int>(d.month) << '-'
+ << setw(2) << static_cast<int>(d.day);
os.flags(flags);
os.fill(fill);
return os;
@@ -53,9 +53,9 @@
{
char fill = os.fill('0');
ios::fmtflags flags = os.setf(ios::right);
- os << setw(2) << t.hour << ':'
- << setw(2) << t.minute << ':'
- << setw(2) << t.second;
+ os << setw(2) << static_cast<int>(t.hour) << ':'
+ << setw(2) << static_cast<int>(t.minute) << ':'
+ << setw(2) << static_cast<int>(t.second);
os.flags(flags);
os.fill(fill);
return os;
Index: lib/custom.pl
===================================================================
--- lib/custom.pl (revision 1163)
+++ lib/custom.pl (working copy)
@@ -262,7 +262,7 @@
$parm_simple2c_b .= ", " unless $j == $i;
$defs .= " T$j I$j;";
$defs .= "\n" unless $j == $i;
- $popul .= " s->I$j = static_cast<T$j>(row.at(O$j));";
+ $popul .= " s->I$j = row.at(O$j).conv (T$j ());";
$popul .= "\n" unless $j == $i;
$names .= " N$j ";
$names .= ",\n" unless $j == $i;
Index: lib/manip.h
===================================================================
--- lib/manip.h (revision 1163)
+++ lib/manip.h (working copy)
@@ -201,6 +201,18 @@
return *o.ostr << '\'' << in << '\'';
}
+
+template <class T, class B>
+MYSQLPP_EXPORT inline std::ostream& operator <<(quote_type1 o,
+ const Null<T, B>& in)
+{
+ if (in.is_null)
+ return *o.ostr << "NULL";
+ else
+ return o << in.data; // quote again
+}
+
+
#endif // !defined(DOXYGEN_IGNORE)
@@ -313,6 +325,18 @@
return *o.ostr << '\'' << in << '\'';
}
+
+template <class T, class B>
+MYSQLPP_EXPORT inline std::ostream& operator <<(quote_only_type1 o,
+ const Null<T, B>& in)
+{
+ if (in.is_null)
+ return *o.ostr << "NULL";
+ else
+ return o << in.data; // quote again
+}
+
+
#endif // !defined(DOXYGEN_IGNORE)
@@ -427,6 +451,18 @@
return *o.ostr << '"' << in << '"';
}
+
+template <class T, class B>
+MYSQLPP_EXPORT inline std::ostream& operator <<(quote_double_only_type1 o,
+ const Null<T, B>& in)
+{
+ if (in.is_null)
+ return *o.ostr << "NULL";
+ else
+ return o << in.data; // quote again
+}
+
+
#endif // !defined(DOXYGEN_IGNORE)
Index: lib/convert.h
===================================================================
--- lib/convert.h (revision 1163)
+++ lib/convert.h (working copy)
@@ -34,8 +34,10 @@
#include "platform.h"
#include "defs.h"
+#include "datetime.h"
#include <stdlib.h>
+#include <string>
namespace mysqlpp {
@@ -113,6 +115,63 @@
#endif // !defined(DOXYGEN_IGNORE)
+template <>
+class mysql_convert<std::string>
+{
+ std::string m_str;
+
+public:
+ mysql_convert (const char* str, const char *& end) :
+ m_str (str)
+ {
+ end = str + m_str.size ();
+ }
+
+ operator std::string () { return m_str; }
+};
+
+template <>
+class mysql_convert<Date>
+{
+ Date m_data;
+
+public:
+ mysql_convert (const char* str, const char *& end)
+ {
+ end = m_data.convert (str);
+ }
+
+ operator Date () { return m_data; }
+};
+
+template <>
+class mysql_convert<DateTime>
+{
+ DateTime m_data;
+
+public:
+ mysql_convert (const char* str, const char *& end)
+ {
+ end = m_data.convert (str);
+ }
+
+ operator DateTime () { return m_data; }
+};
+
+template <>
+class mysql_convert<Time>
+{
+ Time m_data;
+
+public:
+ mysql_convert (const char* str, const char *& end)
+ {
+ end = m_data.convert (str);
+ }
+
+ operator Time () { return m_data; }
+};
+
} // end namespace mysqlpp
#endif
Index: examples/custom7.cpp
===================================================================
--- examples/custom7.cpp (revision 0)
+++ examples/custom7.cpp (revision 0)
@@ -0,0 +1,155 @@
+/***********************************************************************
+ custom7.cpp - This example demonstrates the use of the Null types
+ inside SSQLS structures. You should get a grasp of the
+ involved concepts through the previous examples first.
+
+ Copyright (c) 1998 by Kevin Atkinson, (c) 1999, 2000 and 2001 by
+ MySQL AB, and (c) 2004, 2005 by Educational Technology Resources, Inc.
+ Others may also hold copyrights on code in this file. See the CREDITS
+ 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
+***********************************************************************/
+
+#include "util.h"
+
+#include <mysql++.h>
+#include <custom.h>
+
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+#include <vector>
+
+using namespace std;
+
+// This is the same kind of structures than in the previous custom examples,
+// however this one deals with null strings, int and dates.
+sql_create_4(stock2,
+ 1, 4,
+ int, id,
+ mysqlpp::NullString, name,
+ mysqlpp::Null<int>, qtty,
+ mysqlpp::Null<mysqlpp::Date>, eta)
+
+// Simple exception class for reporting testing errors
+struct TestError : mysqlpp::Exception
+{ TestError (const std::string &w) : mysqlpp::Exception (w) {} };
+
+int
+main(int argc, char *argv[])
+{
+ // Wrap all MySQL++ interactions in one big try block, so any
+ // errors are handled gracefully.
+ try {
+ // Establish the connection to the database server.
+ mysqlpp::Connection con(mysqlpp::use_exceptions);
+ if (!connect_to_db(argc, argv, con)) {
+ return 1;
+ }
+ mysqlpp::Query q = con.query ();
+
+ // Let's start by inserting some rows with null items in our
+ // stock2 table.
+ cout << "Populating stock2..." << endl;
+ q << "delete from stock2";
+ q.execute ();
+ // Notice that we have to give a string to the stock2 ctor
+ // here, not a char* as C++ does not allow for more than
+ // one explicit construction (char* -> string -> Null<string>)
+ q.insert (stock2 (0, string ("Pickle Relish"), 5,
+ mysqlpp::null));
+ q.execute ();
+ q.insert (stock2 (1, mysqlpp::null, mysqlpp::null,
+ mysqlpp::Date (2006, 2, 3)));
+ q.execute ();
+ q.insert (stock2 (2, mysqlpp::null, mysqlpp::null,
+ mysqlpp::null));
+ q.execute ();
+
+ // Display its contents to the user, in a manner independant of
+ // the new code (null-in-SSQLS)
+ q << "select * from stock2";
+ mysqlpp::Result res = q.store ();
+ cout << "stock2 now contains:" << endl;
+ cout << " ID | Name | Qtty | ETA " << endl;
+ cout << "----+---------------+------+------------" << endl;
+ for (size_t i = 0; i < res.size (); i++)
+ {
+ mysqlpp::Row row = res.at (i);
+ cout << setw(3) << row["id"] << " | "
+ << setw(13) << row["name"] << " | "
+ << setw(4) << row["qtty"] << " | "
+ << row["eta"] << endl;
+ }
+ cout << endl;
+
+ // Now read back the values in SSQLS mode and compare them.
+ cout << "Reading again the values in SSQLS mode:" << endl;
+ vector<stock2> res2;
+ q << "select * from stock2";
+ q.storein (res2);
+ if (res.size () != res2.size ())
+ throw TestError ("The size of the results differ!");
+ for (size_t i = 0; i < res.size (); i++)
+ {
+ mysqlpp::Row row = res.at (i);
+ stock2 st = res2.at (i);
+ if (row["name"].is_null () != st.name.is_null
+ || row["qtty"].is_null () != st.qtty.is_null
+ || row["eta"].is_null () != st.eta.is_null)
+ throw TestError ("At least one null status differs!");
+
+ stringstream ss1, ss2;
+ mysqlpp::Null<int> sample_null_int;
+ mysqlpp::Null<mysqlpp::Date> sample_null_date;
+ // In order to get the same quoting mode, we have to
+ // convert the ColData to Nulls. We'll use the conv()
+ // member function for that. It takes a sample of the
+ // type we request.
+ ss1 << row["name"].conv (mysqlpp::NullString ()) << ","
+ << row["qtty"].conv (sample_null_int) << ","
+ << row["eta"].conv (sample_null_date);
+ ss2 << st.name << "," << st.qtty << "," <<
st.eta;
+ if (ss1.str () != ss2.str ())
+ throw TestError ("At least one row differs:\n"+
+ ss1.str ()+"\n"+ss2.str ()+"\n");
+ }
+
+ cout << "They are exactly identical!" << endl;
+ }
+ catch (const mysqlpp::BadQuery& er) {
+ // Handle any query errors
+ cerr << "Query error: " << er.what() << endl;
+ return -1;
+ }
+ catch (const mysqlpp::BadConversion& er) {
+ // Handle bad conversions; e.g. type mismatch populating 'stock'
+ cerr << "Conversion error: " << er.what() << endl <<
+ "\tretrieved data size: " << er.retrieved <<
+ ", actual size: " << er.actual_size << endl;
+ return -1;
+ }
+ catch (const mysqlpp::Exception& er) {
+ // Catch-all for any other MySQL++ exceptions
+ cerr << "Error: " << er.what() << endl;
+ return -1;
+ }
+
+ return 0;
+}
Property changes on: examples/custom7.cpp
___________________________________________________________________
Name: svn:keywords
+ Id LastChangedRevision
Index: examples/Makefile.am
===================================================================
--- examples/Makefile.am (revision 1163)
+++ examples/Makefile.am (working copy)
@@ -27,7 +27,7 @@
noinst_PROGRAMS = resetdb simple1 simple2 simple3 usequery multiquery \
custom1 custom2 custom3 custom4 custom5 custom6 fieldinf1 \
- dbinfo updel load_file cgi_image
+ dbinfo updel load_file cgi_image custom7
noinst_HEADERS = util.h
@@ -70,6 +70,9 @@
custom6_SOURCES = custom6.cpp util.cpp
custom6_DEPENDENCIES = $(MYSQLPP_LIB)
+custom7_SOURCES = custom7.cpp util.cpp
+custom7_DEPENDENCIES = $(MYSQLPP_LIB)
+
fieldinf1_SOURCES = fieldinf1.cpp util.cpp
fieldinf1_DEPENDENCIES = $(MYSQLPP_LIB)
Index: examples/resetdb.cpp
===================================================================
--- examples/resetdb.cpp (revision 1163)
+++ examples/resetdb.cpp (working copy)
@@ -60,6 +60,7 @@
// really care, as it'll get created next.
cout << "Dropping existing stock table..." << endl;
query.execute("drop table stock");
+ query.execute("drop table stock2");
}
else {
// Database doesn't exist yet, so create and select it.
@@ -105,6 +106,12 @@
cout << (new_db ? "Created" : "Reinitialized") <<
" sample database successfully." << endl;
+
+ // The stock2 table introduces a null string, needed to test
+ // custom7.
+ cout << "Creating new stock2 table..." << endl;
+ query.execute ("create table stock2 (id int primary key, "
+ " name varchar(20), qtty int, eta date)");
}
catch (const mysqlpp::BadQuery& er) {
// Handle any query errors
Attachment: [application/pgp-signature] Digital signature signature.asc