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 1 | Warren Young | 22 Dec |