List:MySQL++« Previous MessageNext Message »
From:Warren Young Date:December 22 2007 3:17pm
Subject:BETA RELEASE: v3.0.0 beta 1
View as plain text  
It seems appropriate to me that I'm making this release on the first day 
past the Winter solstice: from here on, things will be getting brighter 
around here.  :)

It's been a bit of a slog, but here it is, the first feature-complete 
beta release of what will become MySQL++ v3.0.  This is a very big 
release.  Rough estimate, about 50% bigger than v2.0.

	http://tangentsoft.net/mysql++/test/mysql++-3.0.0-beta1.tar.gz

Due to the timing, this first beta cycle will probably last at least a 
week into the new year, to give all those people who use MySQL++ only in 
a commercial environment a chance to play with it even if they are among 
those that take the week off between Christmas and New Year's Day.  I'll 
be out of the office myself for much of this time, so be patient about 
posts to the list.  A turnaround time of just a few days will be "fast" 
during this time.

The most important thing to read is the "breakages" chapter of the user 
manual.  There's a copy in the tarball, but I've temporarily put up the 
beta version of the docs here:

	http://tangentsoft.net/mysql++/test/doc/

The direct link to the v3 breakages section is:

http://tangentsoft.net/mysql++/test/doc/userman/breakages.html#v3.0.0

Take your time going through that list before you start building your 
programs against it.  This is the first time in about two and a half 
years that I've been able to break the ABI, and I took full advantage of 
that freedom.  This is not a drop-in replacement for v2.3!

All of this is at least somewhat up for discussion still, so don't feel 
shy about challenging it.  While I'd really like to put this release to 
bed, I'm willing to hold it in beta status as long as necessary to 
address any design concerns.

For the brave, here's the big list of changes.  Be warned: printed, it's 
about 8 pages long.  Eeek!

     o Added ConnectionPool class, primarily to let multithreaded
       programs share a set of Connection objects safely in situations
       where it isn't acceptable to have a Connection per thread.

     o Added RefCountedPointer template and RefCountedBuffer class.
       While these may be useful for end user code, they're only
       intended for use within the library.  But even if you never use
       them directly, it's useful to know about them because they enable
       a lot of data sharing and decoupling that wasn't possible before.
       Below, wherever we refer to reference counting, know that the
       feature is implemented using one of these mechanisms.  Jonathan
       Wakely did a lot of very helpful work on this.

     o Several improvements to Specialized SQL Structures (SSQLS):

       - They're finally compatible with Null<>-wrapped types.  This
         feature is based on the "Waba" patch posted to the mailing
         list back in the v2.0 days but with many changes, partly
         because of changes in the underlying library since those days,
         but also to be less intrusive.

       - It's no longer necessary to define a different SSQLS for each
         different field set you use in queries.  That is to say,
         you can define an SSQLS for an entire table and store just a
         subset of the table in it now, with the other fields keeping
         default values.  A side benefit is that the order of the fields
         in the SSQLS no longer has to match the order of fields in
         the result set.  Removed examples/custom6.cpp and reworked
         custom1.cpp to demonstrate what custom6 used to, implicitly.

       - It's now possible to use mysqlpp::String, Date, DateTime, and
         Time types in the key field positions in an SSQLS as we can
         now compare them.

       - Removed "basic" variants of SSQLS creation macros.  They've
         been unofficially deprecated by dint of being all but
         undocumented and unexemplified for a very long time now.

       - You can now use 'bool' type in SSQLS.

     o You can now use mysqlpp::null as a template query parameter to
       get a SQL null.

     o Replaced template ColData_Tmpl<T>:

       - Used to have typedef ColData_Tmpl<std::string> MutableColData.
         It was used only once within MySQL++ itself, and was never
         documented as a class for end users.  This one use within
         the library was a crock, so we just replaced this use with
         std::string and removed the typedef.

       - This left just one use of ColData_Tmpl<T>, instantiating it
         with the MySQL++ utility class const_string, basically a
         clone of std::string with all the mutating features removed.
         Folded the functionality of const_string into the template,
         renamed the result to String, and deleted the const_string
         class.  It'd be a complete std::string replacement -- with
         SQL-related enhancements -- if it were modifiable, but MySQL++
         doesn't need it to be modifiable, so it's still the closest
         thing MySQL++ has to its own "string type".  Thus the name.

       - Replaced the internal buffer management of String with a much
         more clever reference-counted scheme.  This shows its greatest
         advantage in the return from Row::operator[]() and such, which
         for technical reasons must still return by value, not by
         reference as is more common for this operator.  Because it
         uses reference counting, this doesn't copy the buffer, so you
         can index into a Row to get a BLOB column and not worry about
         the additional copy it used to make.

     o Redesigned SQLString:

       - It used to derive from std::string, and while MySQL++'s
         internals did use it in place of std::string, these places
         didn't take advantage of the additional features offered
         by SQLString.  So, replaced all those uses with std::string.

       - All the remaining uses are MySQL++ public interfaces that
         need to be able to accept any of many different data types,
         and we want that data to be automatically converted to a
         SQL-compatible string form.  Because it no longer has the
         parentage to be a general-purpose string type and MySQL++ has
         a new contender for that role (String), renamed SQLString to
         SQLTypeAdapter to reflect its new, limited purpose.  ("STA"
         for short.)

       - Since we don't have the std::string base class to manage the
         string buffer any more, using the same reference counted
         buffer mechanism as String.  In addition to saving code by
         not creating yet another buffer management mechanism, it means
         objects of the two classes can share a buffer when you assign
         one to the other or pass one to the other's copy ctor.

       - Added many more conversion ctors.

       - SQLTypeAdapter mechanisms using the C char data type now
         treat them as single-character strings instead of one-byte
         integers.

       - Added tinyint interfaces to SQLTypeAdapter to replace the
         former char interfaces.

     o As a result of the ColData -> String redesign, removed
       Row::raw_*().  Before String copies were efficient, this was
       helpful in accessing BLOB data.  It was doubly helpful before
       String dealt correctly with embedded null characters, but that
       reason is gone now, too.

     o Row::operator[](const char*) no longer unconditionally throws the
       BadFieldName exception when you ask for a field that doesn't
       exist.  It will still throw it if exceptions are enabled, but if
       not, it'll just return an empty String.  This was necessary to
       make the SSQLS subset and field order independence features work.

     o Similarly, Result::field_num() returns -1 when you ask for
       a field that doesn't exist instead of throwing BadFieldName if
       exceptions are disabled.

     o You can now use the OptionalExceptions mechanism to disable
       exceptions on const MySQL++ objects.

     o Redesigned query result classes:

       - Instead of Result deriving from ResUse, the two derive from
         a common base class -- ResultBase -- containing the bits that
         are truly the same between them.  Before, Result inherited
         several methods that didn't really make sense for "store"
         query result sets.

       - Renamed Result to StoreQueryResult and ResUse to UseQueryResult
         so it's clearer what each is for.

       - Renamed ResNSel to SimpleResult.

       - Made all SimpleResult data members private and hid them behind
         const accessor functions of the same name.

       - The result set classes all used to be friends of Connection
         for various lame reasons.  Since they are created by Query,
         and Query has a good reason for a strong relationship with
         Connection, moved Connection access out of each result set
         class into the code in Query that creates that type of result
         set object.

       - StoreQueryResult now derives from vector<Row> in addition to
         ResultBase; it used to merely emulate a vector of Rows, poorly.
         It can now dispose of the MYSQL_RESULT at the end of object
         construction, because it creates all the Row objects up front
         instead of on the fly.  And as a result of *that*, operator[]
         returns by reference instead of by value, operator -> works
         correctly on iterators, all STL algorithms work, etc., etc.

       - IMPORTANT COMPATIBILITY BREAK: because we used fetch_row()
         stuff in Result previously, it was okay to index past the
         end of the result set: you'd just get a falsy Row when you
         did this, just as happens when doing the same thing in a
         "use" query.  The simple1 and simple2 examples did this,
         so it's likely that code exists that takes advantage of this
         misfeature.  New versions of these examples show how to index
         through a StoreQueryResult without running past its end.

       - ResUse used to delay creation of its FieldNames and FieldTypes
         objects until the point of need.  This had several implications
         for thread and exception safety that we fix by just creating
         them in the ctor.  If your code is multi-threaded and was
         avoiding certain usage patterns due to crashes, it's worth
         trying your preferred way again.

       - Removed a bunch of unnecessary alias methods:

         - columns() -> num_fields()
         - names()   -> field_names()
         - rows()    -> num_rows()
         - types()   -> field_types()

       - Renamed several methods for grammar reasons:

         - fields(unsigned int)      -> field(unsigned int)
         - names(const std::string&) -> field_num(const std::string&)
         - names(int)                -> field_name(int)
         - types(int)                -> field_type(int)

       - Removed several "smelly" methods:

         - purge()
         - raw_result()
         - reset_names()
         - reset_field_names()
         - reset_types()
         - reset_field_types()

       - Several data members held by result set objects were common to
         all Row objects we kept, so when creating the Row we'd pass a
         pointer to ourselves so they could call back up to the
         result object to get access to this.  This was all nice and
         efficient, except that it required that the result set object
         outlive all row objects it created.  Now we're storing these in
         reference-counted data structures and passing them to the
         Row so the "last one out can turn out the lights" so to speak.

       - A non-obvious side benefit of the previous change is that
         you can now use Query::storein() with an STL container of
         Row objects now, instead of having to use SSQLSes.  This used
         to be a guaranteed way to crash a program before, due to the
         lifetime issue.

       - Copying result objects wasn't possible before.  Copy ctors
         did exist, but they did a "move" instead of a copy: the new
         object gained ownership of all held data, and the old one
         relinquished all its data.  This made returning result set
         objects by value efficient, but constrained the ways you could
         use these objects.  Now that the result sets use reference
         counting for so much of the data they hold, true copies are
         now possible without losing efficiency.

     o Field class used to just be a typedef for the corresponding C
       API class.  Now it's a real C++ class providing a more MySQL++
       sort of interface, plus good OO things like information hiding
       and implementation detail abstraction.  If you were accessing
       data in the Field structure before, it's likely that you'll
       have to make code changes, if only to call accessor methods
       instead of accessing the fields directly.  In addition to the
       reference manual documentation for field.h, see the fieldinf.cpp
       and dbinfo.cpp examples: they access Field the new way now.

     o Fields class was basically a specialized std::vector work-alike
       for dealing with the C API to get access to MYSQL_FIELD objects
       and present them as contained Field objects.  New Field type
       let us replace it with "typedef std::vector<Field> Fields"

     o Major improvements to the quoting and escaping mechanisms:

       - One major improvement is due in part to the STA work described
         above.  Because it has so many conversion ctors, all of which
         preserve enough type information for proper SQL query building,
         we were able to remove many specializations and overloads for
         particular data types.  Now almost all quoting and escaping of
         a particular sort happen in functions taking a SQLTypeAdapter.

       - Side effects of above change are that quoting and escaping
         now works correctly for plain C and C++ string types.

       - Fixed a bug in quote_double_only manipulator for String: was
         using single quotes by mistake.

       - Custom stream manipulators for escaping and quoting values now
         only work with Query stream.  Inserting them into any other C++
         stream is a no-op.  Likewise, automatic quoting and escaping
         for the specialized string classes String and SQLTypeAdapter
         now only works when it's obvious we're building a SQL query,
         not sending the objects to some other output stream.

       - Added escape_string() member functions to Query and
         SQLQueryParms::escape_string(), and removed the global function
         of the same name.  Because these are tied indirectly to a
         Connection object, this also has the effect that escaping is
         now aware of the current default character set used by the
         database server.  There's only one case where this isn't done
         now, and that's when we're disconnected from the server.

       - Previous two items form a trade-off: if your code was depending
         on the ability to use quoting and escaping manipulators on
         non-Query ostreams, you can build a replacement mechanism
         using these new functions.

       - Removed 'r' and 'R' template query parameter modifiers,
         which meant "always quote" and "always quote and escape"
         regardless of the data type of the parameter.  There are no
         corresponding manipulators (for good reason), so the removal
         restores symmetry.

     o Created DBDriver class to almost completely wrap the low-level
       MySQL C API interface:

       - The class was created from a lot of Connection's and Query's
         guts.

       - Connection creates a DBDriver object upon connection and
         passes a pointer to it down to Query objects it creates.
         In turn, they pass the pointer on to any of their children
         that need access to the C API.

       - Nothing outside DBDriver calls the C API directly now, though
         DBDriver leaks C API data structures quite a lot.  As a
         result, This is merely a tentative first step toward database
         independence.  See the Wishlist for what remains to be done.

     o Completely redesigned the connection option setting mechanism:

       - Connection::set_option() used to be overloaded for every option
         argument type we understood.  They'd also take a
         Connection::Option enum value indicating the option type.
         This design meant you could pass any Option value to any
         set_option() overload, and the resulting argument type error
         wouldn't be caught until run time.

       - Connection::set_option() is no longer overloaded.  It now
         just takes a pointer to one of the new Option subclasses.
         There's a subclass for every connection option we understand,
         and each has member variables of the appropriate type for
         that connection option's arguments.  This new mechanism is
         much more type-safe and object-oriented.

       - Replaced Connection::enable_ssl() with an option, SslOption.

       - Removed compress, connect_timeout, and client_flag parameters
         from Connection's ctor and connect() method.  All of these
         things now have corresponding Option subclasses.  There's about
         a dozen, so rather than list them here, look in lib/options.h.

     o Moved Connection::affected_rows(), info() and insert_id() methods
       to class Query, as they relate to the most recently-executed
       query.

     o Several method name changes in Connection:

       - client_info()   -> client_version()
       - host_info()     -> ipc_info()
       - proto_info()    -> protocol_version()
       - server_info()   -> server_version()
       - stat()          -> status()

     o Removed Connection::api_version().  It does the same thing as
       client_version().

     o Parameterized tiny_int class on the value type so you can
       get both signed and unsigned TINYINTs

     o Changed the sql_tinyint and sql_tinyint_unsigned typedefs to use
       mysqlpp::tiny_int<VT> instead of raw chars

     o Added sql_*text typedefs for things like MEDIUMTEXT

     o Changed sql_timestamp typedef to be for DateTime instead of Time.

     o If you use the default constructor for DateTime and don't
       subsequently set its year, month, day, hour, minute or second
       data members to nonzero values, it becomes the SQL function
       "NOW()" in a query string.

     o Added a DateTime ctor taking discrete year, month, day, hour,
       minute, and second values.

     o The Date, DateTime and Time classes used to have implicit
       conversion constructors for ColData and std::string.  Had to
       turn these into a template ctor for any stringish type and
       then had to make it explicit to make the Null<T> SSQLS support
       mentioned above work.  The new template formulation made these
       classes to "grabby" when the compiler was allowed to do implicit
       conversions through it: the compiler would end up tying itself
       in knots performing bizarre conversions.  Thanks for the basic
       concept of this patch go to "Waba."

     o Added copy ctor and assignment operator to Row.

     o Row::operator[]() takes int now instead of unsigned int.
       This finally (!) makes it possible to say row[0] without the
       compiler giving an ambiguous overload error.

     o Changed all uses of row.at(0) in the examples to row[0]

     o Added operator[] to all classes that only had at().

     o Query now automatically resets itself when inserting a new query
       string into it when it holds an old query string that has been
       executed already.  This removes the need to call Query::reset()
       when reusing a query object for most forms of query building.
       The exception is when using template queries: we can't auto-reset
       because resetting throws away parsed template and the defaults.
       The examples use reset() only when necessary, so emulate them.
       It's safe to call reset() anyway, just wasteful.

     o Removed reset_query parameter from all Query methods.  It never
       worked, and above change implements the promise.

     o Query::store_next() and Result::fetch_row() no longer throw
       the EndOfResults and EndOfResultSets exceptions; these are not
       exceptional conditions!  These methods simply return false now.

     o Removed examples/usequery.cpp: there's no essential difference
       between what it did and what examples/simple3.cpp does now as
       a result of the previous change.

     o Added Query::exec(void), paralleling Query::execute(void).

     o Removed Query::preview().  The most direct replacement for this
       set of overloaded methods is the parallel set of str() methods,
       which were just aliases before.  (Chose str() over preview()
       because it's standard C++ nomenclature.)  But if you're just
       looking to get a copy of a built query string and you aren't
       using template queries, you can now insert the Query into a
       stream and get the same result.  A lot of code in the examples
       saying things like "cout << query.preview() << endl" now says
       "cout << query << endl" instead, for example.

     o Removed overloads of Query::execute(), store(), and use()
       that take only a const char*.  This is only an ABI change:
       code that relied on these being available will just call the
       versions taking a single SQLTypeAdapter.  This just snaps a
       layer of indirection.

     o Renamed Query::def to Query::template_defaults to make its
       purpose clearer.

     o Query::error() now returns const char*, not a std::string by
       value.  There's no point in making a copy of the error string.
       The method is now const as well, as it doesn't change the
       Query object.

     o Added Query::errnum(), which just wraps Connection::errnum().

     o Added error number parameters and accessor functions to BadQuery,
       ConnectionFailed and DBSelectionFailed exceptions, to preserve
       the state of Connection::errnum() at the point of the exception,
       so you don't have to rely on this value remaining unchanged
       during the exception throw process.  All places that use these
       exceptions now include this value where possible.  Thanks for the
       initial patch go to Jim Wallace.

     o Removed Lockable mechanism from Connection and Query; it was
       conceptually flawed.  See the new user manual chapter on
       threading for advice on using MySQL++ safely without locking.
       There is mutex locking now in ConnectionPool, but that's it.

     o Connection::query() now takes an optional query string, allowing
       the returned Query object to start off with a value.  Especially
       useful when the query string is static, either because it's
       a simple query or because it's a template.  You can now build
       chains like "if (conn.query("CREATE INDEX ...").exec()) { ..."

     o Added Connection::thread_aware(), thread_end(), thread_id()
       and thread_safe().  See user manual's threading chapter for
       explanations.

     o Renamed "success" data members in Connection, Query and
       SimpleResult (neé ResNSel) to "copacetic_", making them private
       if they weren't before.  This better reflects their actual
       use, which isn't to say that there has necessarily been actual
       success, but rather that everything's okay with the object.

     o Removed success() member functions from above classes.  All can
       be tested in bool context to get the same information.

     o Replaced all operator bool()s in MySQL++ classes with safer
       alternatives.  See http://www.artima.com/cppsource/safebool.html
       Thanks to Jonathan Wakely and Joseph Artsimovich for much
       helpful commentary, advice, and code used in these mechanisms.

     o Decoupled Connection::copacetic_ from Connection::is_connected_.
       It is now possible for the object to be copacetic without being
       connected.  However, if it tries to connect and fails, then
       it is not copacetic.  If it is copacetic and not connected, it
       means we haven't even tried to connect yet, a useful distinction.

     o Collapsed Connection's host, port, and socket_name down into
       a new combined 'server' parameter which is parsed to determine
       what kind of connection you mean.  These interfaces are still
       compatible with v2.3 and earlier up through the port parameter.
       There are differences beyond this.

     o Added TCPConnection, UnixDomainSocketConnection and
       WindowsNamedPipeConnection subclasses for Connection giving
       simpler construction and connect() method interfaces for
       instances where you know what kind of connection you want at
       compile time.

     o Changed Connection::ping() return value from int to bool.

     o Renamed NullisNull to NullIsNull -- capital I -- and similar for
       NullisZero and NullisBlank.

     o Way back in v1.7.x we used the BadQuery exception for all kinds
       of exceptional conditions, not just bad queries.  Replaced
       most of these in v2.0.0 with new dedicated exceptions, but a
       few remained:

       - Errors that occur during the processing of a "use" query after
         the query itself executes correctly now throw UseQueryError.
         It's not a "bad query", because the query executed
         successfully.  It just choked during subsequent processing,
         so it's a different exception.  Thanks for this patch go to
         Jim Wallace.

       - Replaced BadQuery exceptions thrown in Row constructor due
         to bad ctor parameters with new ObjectNotInitialized exception
         This is also Jim Wallace's work.

     o The examples now all use getopt() type command line options
       instead of positional options.  This makes it possible to
       pass options in any order, leave at their default options that
       used to be in the middle of the sequence, and offer different
       subsets of options for different programs.  Also allows for
       special internal-use options, like -D passed by dtest to let
       examples change their behavior when run under dtest to produce
       only predictable output.

     o Split old libutil functionality into two modules, one holding
       all the "print data" functions, and another holding all the
       command line parsing stuff.  This makes it easier for newbies
       to ignore the command line stuff, treating it like a black box.
       The wish to understand the "print data" routines is much more
       common, so the two needed to be disentangled.

     o Renamed examples' libutil to libexcommon.

     o Removed connect_to_db() libutil function.  It combined command
       line parsing, which users don't care about, with database
       connection establishment, which they do care about.  Now the
       examples just call out to libexcommon to parse the command
       line, and use the values they get back to explicitly make the
       connection, so it isn't hidden.

     o Redesigned dbinfo example's output to be easier to read.

     o Fixed an output formatting bug created in 2.3.0 that caused the
       tabular output from examples to not line up.

     o Renamed examples/tquery.cpp to tquery1.cpp and created
       examples/tquery2.cpp to demonstrate passing parameters via a
       SQLQueryParametrs object instead of discretely.

     o Renamed fieldinf1.cpp example to fieldinf.cpp, and simplified
       its output so it can be part of the dtest sequence.

     o Renamed examples/xaction.cpp to transaction.cpp.  It created too
       much cognotive dissonance whenever thinking about both it and
       lib/transaction.cpp.

     o Added examples/deadlock.cpp, to test handling of exceptions due
       to server-side transaction deadlock detection.  Also added
       code to resetdb to create a table needed to test this.
       Initial version created by Jim Wallace to test the value of
       all his BadQuery exception work, with reworking by me.

     o Greatly expanded dtest suite.  Still very low coverage ratio,
       but compared to previous release, it's a big improvement.

     o Optimized #includes, especially in lib/*.h to reduce
       dependencies and thus compile time when one of these changes.

     o Fixed a typo in RPM filename generation that prevented -devel
       RPM from recognizing that the corresponding MySQL++ library
       RPM was installed.

     o ...plus dozens of small bug fixes and internal enhancements,
       many documentation improvements, and expansion of support for
       newer operating systems and compilers.
Thread
BETA RELEASE: v3.0.0 beta 1Warren Young22 Dec