This chapter documents those library changes since the epochal
1.7.9 release that break end-user programs. You can dig this stuff out
of the ChangeLog.md
file, but the change log
focuses more on explaining and justifying the facets of each change,
while this section focuses on how to migrate your code between these
library versions.
Since pure additions do not break programs, those changes are still documented only in the change log.
This section documents files, functions, methods and classes that were removed or changed in an incompatible way. If your program uses the changed item, you will have to change something in your program to get it to compile after upgrading to each of these versions.
Removed Row::operator[]()
overloads
except the one for size_type, and added
Row::lookup_by_name()
to provide the
“subscript by string” functionality. In practical
terms, this change means that the row["field"]
syntax no longer works; you must use the new
lookup_by_name
method instead.
Renamed the generated library on POSIX systems from
libsqlplus
to
libmysqlpp
.
Removed SQLQuery::operator=()
, and
the same for its Query
subclass. Use the
copy constructor instead, if you need to copy one query to another
query object.
The library used to have two names for many core classes: a
short one, such as Row
and a longer one,
MysqlRow
. The library now uses the shorter
names exclusively.
All symbols within MySQL++ are in the
mysqlpp
namespace now if you use the new
mysql++.h
header. If you use the older
sqlplus.hh
or mysql++.hh
headers, these symbols are hoist up into the global namespace. The
older headers cause the compiler to emit warnings if you use them,
and they will go away someday.
Connection::create_db()
and drop_db()
return
true on success. They returned
false in v1.7.x! This
change will only affect your code if you have exceptions
disabled.
Renamed
Connection::real_connect()
to connect()
, made several
more of its parameters default, and removed the
old connect()
method, as
it’s now a strict subset of the new one. The
only practical consequence is that if your program
was using real_connect()
,
you will have to change it to
connect()
.
Replaced
Connection::read_option()
with new
set_option()
mechanism. In addition
to changing the name, programs using this function will have
to use the new Connection::Option
enumerated values, accept a true
return value as meaning success instead of 0, and
use the proper argument type. Regarding the latter,
read_option()
took a const
char* argument, but because it was just a thin wrapper
over the MySQL C API function mysql_options(), the actual value being pointed to could
be any of several types. This new mechanism is properly
type-safe.
Classes Connection
,
Query
, Result
,
ResUse
, and Row
now derive from OptionalExceptions which gives these classes a common
interface for disabling exceptions. In addition, almost all
of the per-method exception-disabling flags were removed. The
preferred method for disabling exceptions on these objects
is to create an instance of the new NoExceptions class on the stack, which disables
exceptions on an OptionalExceptions
subclass as long as the NoExceptions
instance is in scope. You can instead call
disable_exceptions()
on any
of these objects, but if you only want them disabled
temporarily, it’s easy to forget to re-enable them
later.
In the previous version of MySQL++,
those classes that supported optional exceptions that
could create instances of other such classes were
supposed to pass this flag on to their children. That
is, if you created a Connection
object with exceptions enabled, and then asked it to
create a Query
object, the
Query
object also had exceptions
disabled. The problem is, this didn’t happen in all
cases where it should have in v1.7. This bug is fixed in
v2.0. If your program begins crashing due to uncaught
exceptions after upgrading to v2.0, this is the most likely
cause. The most expeditious fix in this situation is to
use the new NoExceptions
feature to
return these code paths to the v1.7 behavior. A better fix
is to rework your program to avoid or deal with the new
exceptions.
All custom MySQL++ exceptions now derive from
the new Exception interface.
The practical upshot of this is that the variability between
the various exception types has been eliminated. For instance,
to get the error string, the BadQuery
exception had a string member called error
plus a method called what()
. Both
did the same thing, and the what()
method is more common, so the error string was dropped
from the interface. None of the example programs had to be
changed to work with the new exceptions, so if your program
handles MySQL++ exceptions the same way they do, your program
won’t need to change, either.
Renamed
SQLQueryNEParams
exception to
BadParamCount
to match style of other
exception names.
Added BadOption, ConnectionFailed, DBSelectionFailed, EndOfResults, EndOfResultSets, LockFailed, and ObjectNotInitialized exception types, to fix
overuse of BadQuery
. Now the
latter is used only for errors on query execution. If
your program has a “catch-all” block taking a
std::exception
for each try block
containing MySQL++ statements, you probably won’t
need to change your program. Otherwise, the new exceptions
will likely show up as program crashes due to unhandled
exceptions.
In previous versions,
Connection
had
a querying interface similar to class
Query
’s. These methods were
intended only for Query
’s use; no
example ever used this interface directly, so no end-user code
is likely to be affected by this change.
A more likely problem arising from
the above change is code that tests for query success
by calling the Connection
object’s success()
method
or by casting it to bool. This will now give
misleading results, because queries no longer go through
the Connection
object. Class
Query
has the same success-testing
interface, so use it instead.
Query
now derives
from std::ostream
instead of
std::stringstream
.
Renamed
ResUse::mysql_result()
to
raw_result()
so it’s database
server neutral.
Removed
ResUse::eof()
, as it wrapped
the deprecated and unnecessary MySQL C API function
mysql_eof(). See the
simple3
and usequery
examples to see the proper way to test for the end of a result
set.
Removed “field name” form
of Row::field_list()
. It was
pointless.
Row
subscripting
works more like v1.7.9: one can subscript a
Row
with a string (e.g.
row["myfield"]
), or with
an integer (e.g. row[5]
).
lookup_by_name()
was
removed. Because row[0]
is
ambiguous (0 could mean the first field, or be a null
pointer to const char*), there is now
Row::at()
, which can look up any
field by index.
Where possible, all distributed Makefiles only build dynamic libraries. (Shared objects on most Unices, DLLs on Windows, etc.) Unless your program is licensed under the GPL or LGPL, you shouldn’t have been using the static libraries from previous versions anyway.
Removed the backwards-compatibility
headers sqlplus.hh
and
mysql++.hh
. If you were
still using these, you will have to change to
mysql++.h
, which will put all symbols in
namespace mysqlpp.
Can no longer use arrow operator
(->) on the iterators into the
Fields
, Result
and Row
containers.
Code like this will have to change:
query << "delete from mytable where myfield=%0:myvalue"; query.parse(); query.def["myvalue"] = some_value; query.execute();
...to something more like this:
query << "delete from mytable where myfield=%0"; query.parse(); query.execute(some_value);
The first code snippet abuses the default template query
parameter mechanism (Query::def
) to fill out
the template instead of using one of the overloaded forms of
execute()
,
store()
or use()
taking one or more SQLString
parameters.
The purpose of Query::def
is to allow for
default template parameters over multiple queries. In the first
snippet above, there is only one parameter, so in order to justify
the use of template queries in the first place, it must be
changing with each query. Therefore, it isn’t really a
“default” parameter at all. We did not make this
change maliciously, but you can understand why we are not in any
hurry to restore this “feature”.
(Incidentally, this change was made to allow better support for BLOB columns.)
Connection::set_option()
calls now
set the connection option immediately, instead of waiting until
just before the connnection is actually established. Code that
relied on the old behavior could see unhandled exceptions, since
option setting errors are now thrown from a different part of the
code. You want to wrap the actual
set_option()
call now, not
Connection::connect()
FieldNames
and
FieldTypes
are no longer exported from the
library. If you are using these classes directly from Visual C++
or MinGW, your code won’t be able to dynamically link to a
DLL version of the library any more. These are internal classes,
however, so no one should be using them directly.
Several classes changed names in this release:
ColData
is now
String
.
NullisBlank
is now NullIsBlank
. (Note
the capital I.) Similar
changes for NullisNull
and
NullisZero
.
ResNSel
is now
SimpleResult
.
Result
is now
StoreQueryResult
.
ResUse
is now
UseQueryResult
.
SQLString
is now
SQLTypeAdapter
.
When first building existing code against this version,
you may find it helpful to define the macro
MYSQLPP_OLD_CLASS_NAMES
in your
program’s build options. This will turn on some macros
that set up aliases for the new class names matching their
corresponding old names. Then, when you’ve fixed up any
other issues that may prevent your program from building with
the new MySQL++, you can turn it back off and fix up any class
name differences.
If you were only using ColData
in a
BLOB context, you should use sql_blob
or
one of the related typedefs defined in
lib/sql_types.h
instead, to insulate your
code from changes like these.
The SQLString
change
shouldn’t affect you, as this class was not designed to be
used by end user code. But, due to the old name and the fact
that it used to derive from std::string
,
some might have been tempted to use it as an enhanced
std::string
. Such code will undoubtedly
break, but can probably be fixed by just changing it to use
std::string
instead.
The option setting mechanism has been redesigned. (Yes,
again.) There used to be an enum in
Connection
with a value for each option
we understood, and an overload of
Connection::set_option()
for each
argument type we understood. It was possible to pass any option
value to any set_option()
overload, and
the problem would only be detected at run time. Now each option
is represented by a class derived from the new
Option
abstract base class, and
set_option()
simply takes a pointer to
one of these objects. See
examples/multiquery.cpp
for the syntax.
Since each Option
subclass takes only the
parameter types it actually understands, it’s now
completely type-safe at compile time.
The new option setting mechanism also has the virtue of
being more powerful so it let us replace several existing things
within Connection
with new
options:
Replaced
enable_ssl()
with
SslOption
.
Replaced the compress
parameter to the Connection
create-and-connect constructor and
Connection::connect()
method with
CompressOption
.
Replaced the
connect_timeout
parameter with
ConnectTimeoutOption
.
Defined Option
subclasses for each of the flags you would previously set
using the client_flag
parameter. There
are about a dozen of these, so instead of listing them,
look in lib/options.h
for something
with a similar name.
Collapsed Connection
’s
host
, port
, and
socket_name
parameters 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.
Moved
Connection::affected_rows()
,
info()
and
insert_id()
methods to class
Query
, as they relate to the most
recently-executed query.
Changed the return type of
Connection::ping()
from
int to bool. If you were calling
ping()
in bool context
or using its return value in bool context,
you will need to reverse the sense of the test because the
previous return code used zero to mean success. Now it returns
true to indicate success.
Renamed several methods:
Use client_version()
instead of api_version()
or
client_info()
.
Use
ipc_version()
instead of
host_info()
.
Use
protocol_version()
instead of
proto_info()
.
Use
server_version()
instead of
server_info()
.
Use
status()
instead of
stat()
.
Also, removed close()
in favor
of disconnect()
, which has always
done the same thing.
The sql_timestamp typedef is now
an alias for DateTime
, not
Time
.
There used to be implicit conversion constructors from
ColData
(now
String
),
std::string
and const char*
for the Date
,
DateTime
, and Time
classes. It’s still possible to do these conversions, but
only explicitly. (This had to be done to make
Null<T>
work in SSQLSes.)
The most likely place to run into problems as a result of this change is in code like this:
void some_function(const mysqlpp::DateTime& dt); some_function("2007-12-22");
The function call needs to be changed to:
some_function(mysqlpp::DateTime("2007-12-22"));
If an error occurs during the processing of a
“use” query (as opposed to the initial execution) we
throw the new UseQueryError
exception
instead of BadQuery
.
If you pass bad values to the Row
ctor so that it can’t initialize itself properly, it
throws the ObjectNotInitialized
exception instead of BadQuery
.
Together, these two changes mean that
BadQuery
is now used solely to indicate
a problem executing the actual SQL query statement.
Field
is now a real C++ class,
not just a typedef for the corresponding C API class. Major
portability impacts are:
It has no public data members. Where sensible, there is a public accessor function of the same name as the corresponding field in the C API structure.
The main exception to this is the
flags
data member. This is a bitfield in
the C API data structure and you had to use MySQL-specific
constants to break values out of it. MySQL++’s new
Field
class provides a public member
function returning bool for each of these
flags.
The new class doesn’t include all of the data members from the C API version. We left out those that aren’t used within MySQL++ or its examples, or whose function we couldn’t understand. Basically, if we couldn’t document a reason to use it, we left it out.
Fields
used to be a
std::vector
work-alike which
worked with the C API to access fields and return them
as though they were simply contained directly within the
Fields
object. Now that we have a
real MySQL++ class to hold information about each field
without reference to the C API, we were able to replace the
Fields
class with:
typedef std::vector<Field> Fields;
If anything, this should give a pure superset of the old functionality, but it’s possible it could break end user code.
If you were using char as an 8-bit integer
in query building, there are several places in MySQL++ v3 where
it will now be treated as a single-character string. MySQL++
has had the tiny_int
class for many
years now specifically to provide a true 8-bit integer without
the semantic confusion surrounding the old C char
type. Either use tiny_int
, or
use the SQL type aliases sql_tinyint and
sql_tinyint_unsigned instead.
The ‘r’ and ‘R’ template query
parameter modifiers were removed. They made the library do
quoting and both quoting and escaping (respectively) regardless
of the data type of the parameter. There are no corresponding
Query
stream manipulators, so for
symmetery we had to decide whether to add such manipulators or
remove the tquery modifiers. There should never be a reason to
force quoting or escaping other than to work around a MySQL++
bug, and it’s better to just fix the bug than work around
it, so removed the tquery modifiers.
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 when you hit the end of the result set
now.
Renamed Query::def
to
Query::template_defaults
to make its
purpose clearer.
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.
For example, a lot of code in the examples that used to say things like:
cout << query.preview() << endl;
now looks like this:
cout << query << endl;
In addition to the class name changes described above,
UseQueryResult
is no longer
StoreQueryResult
’s base class.
There is a new abstract class called
ResultBase
containing much of what used
to be in ResUse
, and it is the base of
both of these concrete result set types. This should only affect
your code if you were using ResUse
references to refer to Result
objects.
Removed a bunch of duplicate methods:
Use
num_fields()
instead of
columns()
.
Use
field_names()
instead of
names()
.
Use
num_rows()
instead of
rows()
.
Use
field_types()
instead of
types()
.
Renamed several methods for “grammar” reasons. For example, some methods returned a single object but had a “plural” name, implying that it returned a container of objects. In cases like this, we changed the name to agree with the return value. Some of these also fall into the duplicate method category above:
Use
field(unsigned int)
instead of fields(unsigned
int)
.
Use field_num(const
std::string&)
instead of names(const
std::string&)
.
Use
field_name(int)
instead of
names(int)
.
Use
field_type(int)
instead of
types(int)
.
Removed several “smelly” methods:
purge()
: was an
internal implementation detail, not something for end user
code to call
raw_result()
: end
user code shouldn’t be digging down to the C API data
structures, but if you really need something like this, look
at the implementation of
Query::storein()
. Its workings will
probably be educational.
reset_names()
:
no reason to call this, especially now that the field
name list is initialized once at startup and then never
changed
reset_field_names()
:
just an alias for previous
reset_types()
:
same argument as for
reset_names()
reset_field_types()
:
just an alias for previous
ResUse::field_num()
would
unconditionally throw a BadFieldName
exception when you asked for a field that doesn’t exist.
Now, if exceptions are disabled on the object, it just returns
-1.
SimpleResult
’s member
variables are all now private, and have read-only accessor
functions of the same name.
Code like this used to work:
mysqlpp::Row row; mysqlpp::Result::size_type i; for (i = 0; row = res[i]; ++i) { // Do something with row here }
That is, indexing past the end of a “store”
result set would just return an empty row object, which tests as
false in bool context, so it ends the loop. Now
that StoreQueryResult
is a
std::vector
derivative, this either
crashes your program or causes the standard library to throw an
exception, depending on what debugging features your version of
STL has. The proper technique is:
mysqlpp::Row row; mysqlpp::StoreQueryResult::size_type i; for (i = 0; i < res.num_rows(); ++i) { row = res[i]; // Do something with row here }
...or, in a more C++ish idiom:
mysqlpp::Row row; mysqlpp::StoreQueryResult::const_iterator it; for (it = res.begin(); it != res.end(); ++it) { row = *it; // Do something with row here }
Removed Row::raw_data()
,
raw_size()
and
raw_string()
. These were useful with
BLOB data back when MySQL++ didn’t handle embedded null
characters very well, and when copies of
ColData
objects were expensive. Neither
is true now, so they have no value any more. Equivalent calls
are:
mysqlpp::String s = row[0]; s.data(); // raw_data() equivalent s.length(); // raw_size() equivalent std::string(s.data(), s.length()); // raw_string() equivalent
Row::operator[](const char*)
would unconditionally throw a
BadFieldName
exception when you asked for
a field that doesn’t exist. Now, if exceptions are
disabled on the Row
object, it just
returns a reference to an empty String
object. You can tell when this happens because such an object
tests as false in bool context.
Renamed custom*
to
ssqls*
. There is a backwards-compatibility
header custom.h
which includes
ssqls.h
for you, but it will go away in a
future version of MySQL++.
SSQLSes get populated by field name now, not by field order. In v2, it was absolutely required that your SSQLS had its fields declared in exactly the same order as the fields in the database server, and there could be no gaps. An ALTER TABLE command would almost always necessitate redefining the corresponding SSQLS and rebuilding your program. Some alterations actually made using SSQLS impossible. For the most part, this change just gives your program additional flexibility in the face of future changes. However, code that was taking advantage of this low-level fact will break when moving to v3. Before I explain how, let’s go over the high-level functional changes you’ll find in v3’s SSQLS mechanism.
Because MySQL++ no longer needs the
SSQLS field order to match the SQL field order,
the sql_create_c_order_*
SSQLS creation macro was dropped in v3. We were
also able to drop the ordering parameters from
sql_create_complete_*
. That in turn
means there is no longer a difference between the way it and
sql_create_c_names_*
work, so the latter
was also dropped. Thus, there are now only two groups of SSQLS
creation macros left: sql_create_*
,
which works pretty much as it always has, and
sql_create_complete_*
, which is the same
except for the lack of ordering parameters.
In general, you should be using
sql_create_*
for all SSQLSes unless
you need to use different names for data members in C++ than
you use for the corresponding columns in SQL. In that case,
use sql_create_complete_*
instead.
In v2, it was possible to have different SQL column
names than SSQLS data member names while still using
sql_create_*
if you only used SSQLS
for data retrieval.[25] In
v3, you must use sql_create_complete_*
for absolutely all uses of SSQLS when you want the C++ field
names to differ from the SQL column names.
The new Null<T>
support in
SSQLSes causes an internal compiler error in Visual C++ 2003.
(VC++ 2005 and newer have no trobule with it.) A poll on the
mailing list says there aren’t many people still stuck on
this version, so we just ifdef’d out the SSQLS mechanism
and all the examples that use it when built with VC++ 2003. If
this affects you, see Section 5.15, “SSQLS and Visual C++ 2003” for
suggestions on ways to cope.
If you are using types other than MySQL++’s
sql_* ones [26]
in your SSQLSes, code that previously worked may now see
TypeLookupFailed
exceptions. (This
can be thrown even if exceptions are otherwise disabled in
MySQL++.) This version of MySQL++ is stricter about mapping
SQL to C++ type information, and vice versa. If the library
can’t find a suitable mapping from one type system
to the other, it throws this exception, because its only
other option would be to crash or raise an assertion. This
typically happens when building SQL queries, so you can
probably handle it the same way as if the subsequent
query excecution failed. If you’re catching the
generic mysqlpp::Exception
, your
error handling code might not need to change. If you see
this exception, it does mean you need to look into your
use of data types, though. The table that controls this is
mysql_type_info::types
, defined at the top
of lib/type_info.cpp
. Every data type in
lib/sql_types.h
has a corresponding record
in this table, so if you stick to those types, you’ll
be fine. It’s also okay to use types your C++ compiler
can convert directly to these predefined types.
The _table
static member variable
for each SSQLS is now private. The recommended way to access
this remains unchanged: the table()
static member function.
table()
used to return a modifiable
reference to the table name. Now there are two overloads,
one which returns an unmodifiable pointer to the table name,
and the other which takes const char* so you
can override the default table name. So, the code we used to
recommend for changing the SSQLS’s table name:
my_ssqls_type::table() = "MyTableName";
now needs to be:
my_ssqls_type::table("MyTableName");
MySQL++ does quoting and escaping much more selectively
now. Basically, if the library can tell you’re not
building a SQL query using one of the standard methods, it
assumes you’re outputting values for human consumption, so
it disables quoting and SQL escaping. If you need to build your
own mechanism to replace this, quoting is easy to do, and
Query::escape_string()
can do SQL
escaping for you.
Removed success()
in
Connection
, Query
and SimpleResult
(neé
ResNSel
) and simply made these classes
testable in bool context to get the same
information. An additional change in
Connection
is that it used to be
considered “unsuccessful” when the connection was
down. Since the sense of this test is now whether the object is
in a good state, it only returns false when the
connection attempt fails. Call
Connection::is_connected()
if you just
want to test whether the connection is up.
The debug mode build of the library now has a "_d" suffix for Visual C++, and Xcode. This lets you have both versions installed without conflict. The release build uses the current naming scheme. If you have an existing program building against MySQL++ on these platforms, you’ll need to change your build options to use the new name in debug mode.
Renamed NO_LONG_LONGS
to
MYSQLPP_NO_LONG_LONGS
to avoid a risk of
collision in the global macro namespace.
Most MySQL++ classes with at()
or operator []()
methods now
throw the new BadIndex
exception when you pass an out-of-range index. These
methods variously either did not check their indices,
or threw std::out_of_range
when
passed a bad index.
I say “most” because there is at
least one MySQL++ class that doesn’t follow this
rule. Fields
is just a typedef for a
specialization of std::vector
, and the
Standard has its own rules for index checking.
This section documents those library changes that require you to rebuild your program so that it will link with the new library. Most of the items in the previous section are also ABI changes, but this section is only for those items that shouldn’t require any code changes in your program.
If you were going to rebuild your program after installing the new library anyway, you can probably ignore this section.
Removed “reset query” parameters from several
Query
class members. This is not an API
change, because the parameters were given default values, and the
library would ignore any value other than the default. So, any
program that tried to make them take another value wouldn’t
have worked anyway.
Some freestanding functions didn’t get moved into namespace mysqlpp when that namespace was created. This release fixed that. It doesn’t affect the API if your program’s C++ source files say using namespace mysqlpp within them.
Removed Connection::infoo()
.
(I’d call this an API change if I thought there were any
programs out there actually using this...)
Collapsed the Connection
constructor
taking a bool (for setting the throw_exceptions flag) and the
default constructor into a single constructor using a default for
the parameter.
Classes Connection
and
Query
are now derived from the
Lockable
interface, instead of implementing
their own lock/unlock functions.
In several instances, functions that took objects by value now take them by const reference, for efficiency.
Merged SQLQuery
class’s members
into class Query
.
Merged RowTemplate
class’s
members into class Row
.
Reordered member variable declarations in some classes. The most common instance is when the private section was declared before the public section; it is now the opposite way. This can change the object’s layout in memory, so a program linking to the library must be rebuilt.
Simplified the date and time class hierarchy.
Date used to
derive from mysql_date
,
Time used to derive
from mysql_time
, and DateTime used to derive from
both of those. All three of these classes used to derive
from mysql_dt_base
. All of the
mysql_*
classes’ functionality
and data has been folded into the leaf classes, and now the
only thing shared between them is their dependence on the
DTbase template. Since the
leaf classes’ interface has not changed and end-user
code shouldn’t have been using the other classes, this
shouldn’t affect the API in any practical way.
mysql_type_info
now always
initializes its private num
member.
Previously, this would go uninitialized if you used the default
constructor. Now there is no default ctor, but the ctor taking one
argument (which sets num
) has a default.
Removed reset_query
parameters from
Query
member functions. None of these have
been honored at least going back to v1.7.9, so this is not an API
change. As of this version, Query
now
automatically detects when it can safely reset itself after
executing a query, so it’s not necessary to ask for a reset
except when using template queries.
Removed overloads of
Query::execute()
,
store()
, and
use()
that take only a const
char*. This is not an API change because there was an
equivalent call chain for this already. This change just snaps
a layer of indirection.
Query::error()
is now
const and returns const char* instead
of a std::string
by value.
Removed Lockable
mechanism as it was
conceptually flawed. Connection
and
Query
consequently no longer derive from
Lockable
. Since it was basically useless in
prior versions, it can’t be construed as an API
change.
Connection::thread_aware()
,
thread_start()
and
thread_end()
are now static methods, so
a program can call them before creating a connection. Ditto for
DBDriver
methods of the same name.
ConnectionPool::release()
is now
virtual, so a subclass can override it.
ConnectionPool::grab()
is now
virtual; same reason as above.
Query
can now be tested in
bool context, as was intended for v3.0.0. Had to
change the “safe bool” method signature to make it
happen, so technically it’s an API change, but it’s
still used the same way.
The addition of a few new virtual methods to
ConnectionPool
inadvertently changed
the library ABI. I knew adding fields changed the ABI, but
erroneously assumed that the inverse of that truth — that
adding methods was always safe —
was also true. Adding normal methods is
safe, but adding virtual methods breaks
the ABI because it changes the class’s vtable size.
That left us with two bad choices: either we could come out with a 3.1.1 that removed these methods to restore the prior ABI, or we could just declare this the “new ABI” and move on, resolving not to fall into this trap again. We’ve chosen the latter path.
[25] In MySQL++ v2, data
retreival (Query::storein()
,
SSQLS(const Row& other)
,
etc.) worked fine regardless of whether your SSQLS field names
matched those in the corresponding SQL table, because the
SSQLS was populated by position, not by field name. Thus,
if all you used SSQLS for was data retrieval, you could
define your structures with sql_create_*
in v2. This was never recommended, because such an SSQLS
wouldn’t work with other features of MySQL++ like
Query::insert()
because they depend
on being able to map names from C++ to SQL and back. You
needed to use sql_create_c_names_*
to make these features work in v2 in the face of a naming
scheme difference between C++ and SQL.
[26] These typedefs have been available since MySQL++ v2.1.