MySQL++ has developed into a very complex and powerful library, with many different ways to accomplish the same task. Unfortunately, this means that figuring out how to perform a simple task can be frustrating for new users. In this section we will provide an overview of the most important user-facing components of the library.
The overall process for using MySQL++ is similar to that of most other database access APIs:
Open the connection
Form and execute the query
Iterate through the result set
Go to 2 :)
There is, however, a lot of extra functionality along each step of the way.
A Connection object manages the connection to the MySQL server. You need at least one of these objects to do anything. A Connection object can either create Query objects for you, or you can execute queries directly through the Connection object. The separate Query object is the recommended way as it gives you far more power.
A Query object is the recommended way of building and executing queries. It is subclassed from std::stringstream which means you can write to it like any other C++ stream to form a query. The library includes stream manipulators that make it easy to generate syntactically-correct SQL.
You can also set up template queries with this class. Template queries work something like the C printf() function: you set up a fixed query string with tags inside that indicate where to insert the variable parts. If you have multiple queries that are structurally similar, you simply set up one template query, and use that in the various locations of your program.
A third method for building queries is to use Specialized SQL Structures (SSQLS). This feature presents your results as a C++ data structure, instead of making you access the data through MySQL++ intermediary classes. It also reduces the amount of embedded SQL code your program needs.
The actual data elements in a result set are stored in a special std::string-like class. Objects of this class can automatically convert themselves to any of the basic C data types as well as some additional MySQL++-specific types that are designed to handle those MySQL that don't map well onto the basic C types. For instance, you can convert a MySQL DATETIME field to a MySQL++ DateTime object automatically. If there is a problem in the conversion it will either set a warning flag or throw an exception, depending on how you set the library up.
MySQL++ has a number of different ways of representing query results.
Not all SQL queries return data. An example is CREATE TABLE. For these types of queries, there is a special result type that simply reports the state resulting from the query: whether the query was successful, how many rows it impacted (if any), etc.
The easiest way to retrieve data from MySQL uses a Result object, which includes one or more Row objects. Because these classes are std::vector-like containers, you can treat the result set as a two-dimensional array. For example you can get the 5th item on the 2nd row by simply saying result[1][4]. You can also access row elements by field name, like this: result[2].lookup_by_name("price").
An alternate way of accessing your query results is through a ResUse object. This class acts more like an STL input iterator than a container: you walk through your result set one item at a time, always going forward. You can't seek around in the result set, and you can't know how many results are in the set until you find the end. This method is more efficient when there can be arbitrarily many results, which could pose a memory allocation problem with the previous technique.
The Specialized SQL Structures (SSQLS) feature method above defines C++ structures that match the table structures in your database schema.
We call it the "static" method because the table structure is fixed at compile time; if you change the database schema, you have to change your SSQLS definitions and recompile. If you fail to do this, your program will throw an exception when you try to stuff a result set into an outdated data structure.
The advantage of this method is that your program will require very little embedded SQL code. You can simply execute a query, and receive your results as C++ data structures, which can be accessed just as you would any other structure. The results can be accessed through the Row object, or you can ask the library to dump the results into a sequential or set-associative STL container for you. Consider this:
vector<mystruct> v; Query q = connection.query(); q << "SELECT * FROM mytable"; q.storein(v); for (vector<mystruct>::iterator it = v.begin(); it != v.end(); ++v) { cout << "Price: " << v.price << endl; }
Isn't that slick?
By default, the library throws exceptions derived from std::exception whenever it encounters an error. You can ask the library to set an error flag instead, if you like, but the exceptions carry more information. Not only do they include a string member telling you why the exception was thrown, there are several exception types, so you can distinguish between several types of error within a single try block.