Ulf Wendel

MySQL Workbench is using Connector/C++ pre-alpha snapshot

Eat your own dog food. The latest development version of MySQL Workbench 5.1 successfully runs a pre-alpha snapshot of the MySQL Driver for C++ since a few weeks. Enjoy your pizza at my costs, Andrey (Hristov). I lost my bet. Less than five bugs have been found when migrating MySQL Workbench to Connector/C++.

MySQL Connector/C++ is now being used by two "internal customers": MySQL Workbench and MySQL Connector/OpenOffice.org. And our internal development version of Connector/OpenOffice.org runs on Connector/C++ as well. The preview version of Connector/OpenOffice.org was using the MySQL Client Library (C-API)

Two internal customers, one choice: JDBC like API

The MySQL Workbench team is more than an internal customer. The foundations of the MySQL Driver for C++ have been laid by the Workbench team. MySQL Workbench is written in C++. When the development of MySQL Workbench started the team checked what components from existing GUI tools could be reused. The existing GUI tools had been using a JDBC like internal database interface and so did MySQL Workbench from the very beginning. JDBC is a widely known and well established API. Because MySQL did not offer a Driver for C++, the team decided to developed the predecessor of the MySQL Connector/C++. If you like the idea Connector/C++, give credits to the WB team.

At about the same time when Workbench started its development, Georg (Richter), reactivated his plans of developing Connector/OpenOffice.org. OpenOffice.org is written in C++. The internal internal database API of OpenOffice.org is called SDBC and it is modelled on JDBC 1.0. The new MySQL Driver for C++ implements 75% of the methods of the core interface of JDBC 3.0.

Matrjoschka Connector/C++ – inside the driver

The assorted MySQL Connectors can be divided into two groups. The first group implements the MySQL Client Server Protocol. The second group is implemented as proxy, a wrapper on top of a driver from the first group. Connector/J, the MySQL Client Server Library (C-API), Connector/Net and the MySQL native driver for PHP (mysqlnd) implement the communication protocol. Connector/J is written in Java and the others are written in C/C#. Pretty much every other Driver for XYZ, Connector/XYZ or API for XYZ, connecting a programming language XYZ to MySQL, is a wrapper on top of the C-ish or Java-based protocol implementations.

MySQL Connector/C++ is a wrapper on top of the C-API. It provides you with a C++ API and hides the inconvenient underlying C-API.

MySQL distributes its client library (C-API) under the terms of the GPL. As usual, the FLOSS license exception can be applied in order to utilize the C-API and its library in OpenSource projects that do not use the GPL. Commercial users can get a commercial license, if they need one. Because the MySQL Connector/C++ is implemented as a wrapper on top of the C-API and it is linked against the C-API library at compile time, it inherits the license conditions. MySQL Connector/C++ is dual-licensed as well: GPL (+FLOSS) or commercial license.

Getting Connector/C++

If you want to give Connector/C++ a test drive today (19th November 2008), I suggest that you check out the latest sources from Launchpad. The alpha release is around the corner and the preview code base will not work with the example shown below.

nixnutz@ulflinux:~/tmp> bzr branch lp:~mysql/mysql-connector-cpp/trunk
You have not informed bzr of your launchpad login. If you are attempting a
write operation and it fails, run "bzr launchpad-login YOUR_ID" and try again.
Branched 288 revision(s).
nixnutz@ulflinux:~/tmp> cd trunk

We use CMake for a cross-platform build system that runs on most operating systems. CMake is not a build system itself. CMake generates "native" build files. That can be GNU Makefiles for Linux systems or Visual Studio projects for Windows systems. Therefore, the first step when building Connector/C++ is to invoke CMake. Once its done you can proceed with the build and installation of Connector/C++. Check the README for some additional hints.

nixnutz@ulflinux:~/tmp/trunk> cmake .
-- Check for working C compiler: /usr/local/bin/gcc
-- Check for working C compiler: /usr/local/bin/gcc -- works
[...]-- Build files have been written to: /home/nixnutz/tmp/trunk
nixnutz@ulflinux:~/tmp/trunk> make
Scanning dependencies of target mysqlcppconn
[  1%] Building CXX object driver/CMakeFiles/mysqlcppconn.dir/mysql_connection.o
[...]
Linking CXX executable statement
nixnutz@ulflinux:~/tmp/trunk> sudo make install
Passwort:
Linking CXX shared library CMakeFiles/CMakeRelink.dir/libmysqlcppconn.so
Install the project...
-- Install configuration: ""
-- Install configuration: ""
-- Installing /usr/local/include/cppconn/blob.h
-- Installing /usr/local/include/cppconn/connection.h
-- Installing /usr/local/include/cppconn/datatype.h
-- Installing /usr/local/include/cppconn/driver.h
-- Installing /usr/local/include/cppconn/exception.h
-- Installing /usr/local/include/cppconn/metadata.h
-- Installing /usr/local/include/cppconn/parameter_metadata.h
-- Installing /usr/local/include/cppconn/prepared_statement.h
-- Installing /usr/local/include/cppconn/resultset.h
-- Installing /usr/local/include/cppconn/resultset_metadata.h
-- Installing /usr/local/include/cppconn/statement.h
-- Installing /usr/local/include/cppconn/warning.h
-- Install configuration: ""
-- Installing /usr/local/lib/libmysqlcppconn.so.1
-- Installing /usr/local/lib/libmysqlcppconn-static.a
-- Installing /usr/local/include/cppconn/mysql_connection.h
-- Installing /usr/local/include/cppconn/mysql_driver.h
-- Installing /usr/local/include/cppconn/mysql_exception.h
-- Installing /usr/local/include/cppconn/mysql_util.h
-- Install configuration: ""
-- Install configuration: ""
-- Install configuration: ""

Be warned that, by default, CMake will cache settings in a file called CMakeCache.txt. A common pitfall among CMake beginners is to forget about the cache. If, for example, CMake picks the wrong library when creating the build files and you update the library and invoke CMake again to rebuild the build files, the cache might still point to the wrong library. Whenever you are in doubt that the cache might fool you, remove the cache file and re-run CMake.

Running an example that ships with Connector/C++

The code repository contains several examples demonstrating the use. If you managed to compile Connector/C++, the examples are compiled as well. You will find the source code and the binaries in the directory examples/

nixnutz@ulflinux:~/tmp/trunk> ls -la examples/*.cpp
-rw-r--r-- 1 nixnutz users  8333 19. Nov 07:31 examples/connect.cpp
-rw-r--r-- 1 nixnutz users 10215 19. Nov 07:31 examples/connection_meta_schemaobj.cpp
-rw-r--r-- 1 nixnutz users  6224 19. Nov 07:31 examples/debug.cpp
-rw-r--r-- 1 nixnutz users  7716 19. Nov 07:31 examples/exceptions.cpp
-rw-r--r-- 1 nixnutz users 12263 19. Nov 07:31 examples/prepared_statement.cpp
-rw-r--r-- 1 nixnutz users 10855 19. Nov 07:31 examples/resultset.cpp
-rw-r--r-- 1 nixnutz users 12063 19. Nov 07:31 examples/resultset_meta.cpp
-rw-r--r-- 1 nixnutz users  9106 19. Nov 07:31 examples/resultset_types.cpp
-rw-r--r-- 1 nixnutz users  4282 19. Nov 07:31 examples/standalone_example.cpp
-rw-r--r-- 1 nixnutz users  5362 19. Nov 07:31 examples/statement.cpp

By default the examples will try to connect to localhost via TCP/IP on port 3306 using the user name "root" and the password "root" to access the database/schema "test" . To connect to a different MySQL Server or to use different credentials, you can pass command line parameters to all the examples.

The examples accept up to four optional parameters. The first parameter is the connection URL, followed by the user name, a password and a database/schema name. The concept of a connection URL is new to Connector/C++. It has been introduced after the preview version was published. The connection URL is also the first parameter of the connect() method of the driver class. You can either use TCP/IP or a Unix domain socket to connect to the MySQL Server.

  • tcp://host[:port], default port: 3306, for example: tcp://127.0.0.1:3307
  • unix://path/to/unix_socket_file, for example: unix:///tmp/mysql.sock

nixnutz@ulflinux:~/tmp/trunk> examples/connect tcp://127.0.0.1:3306 root root test
1..1
# Connector/C++ connect basic usage example..
#
#        Test table created
#        Test table populated
#        Running 'SELECT id, label FROM test ORDER BY id ASC'
#                Number of rows res->rowsCount() = 4
#                Fetching row 0 id = 1, label = ''
#                Fetching row 1 id = 2, label = 'a'
#                Fetching row 2 id = 3, label = 'b'
#                Fetching row 3 id = 4, label = 'c'
#        Fetching 'SELECT id FROM test ORDER BY id DESC' using type conversion
#                Fetching row 0#         id (int) = 4#   id (boolean) = true#    id (long) = 4
#                Fetching row 1#         id (int) = 3#   id (boolean) = true#    id (long) = 3
#                Fetching row 2#         id (int) = 2#   id (boolean) = true#    id (long) = 2
#                Fetching row 3#         id (int) = 1#   id (boolean) = true#    id (long) = 1
#        UPDATE indicates 1 affected rows
#                Expecting id = 100, label = 'y' and got id = 100, label = 'y'
#
#        Demo of connection URL syntax
#                unix://path_to_mysql_socket.sock caused expected exception
#                Can't connect to local MySQL server through socket 'path_to_mysql_socket.sock' (2) (MySQL error code: 2002, SQLState: HY000 )
#                tcp://hostname_or_ip[:port] caused expected exception
#                Unknown MySQL server host 'hostname_or_ip[' (1) (MySQL error code: 2005, SQLState: HY000 )
#                tcp://hostname_or_ip[:port] caused expected exception
#                Unknown MySQL server host 'hostname_or_ip[' (1) (MySQL error code: 2005, SQLState: HY000 )
# done!
ok 1

Yes, the "errors" shown at the end of output are thrown intentionally. Its done to demonstrate URL syntax and show how to handle exceptions.

Compiling your own program against Connector/C++

While the examples may serve as a first, yet simple, code snippet collection, they do not tell you immediately which header files you need to include when compiling a program against Connector/C++. The example programs hide this by including two private header files which are not copied over to public places during make install. If you exand the header files, you get something like below.

#include <stdlib.h>
#include <iostream>
#include <sstream>
#include <stdexcept>

#include "mysql_connection.h"
#include "mysql_exception.h"

#include <cppconn/driver.h>
#include <cppconn/metadata.h>
#include <cppconn/prepared_statement.h>
#include <cppconn/resultset.h>
#include <cppconn/resultset_metadata.h>
#include <cppconn/statement.h>


#include <cppconn/warning.h>

#define EXAMPLE_HOST "tcp://127.0.0.1:3306"
#define EXAMPLE_USER "root"
#define EXAMPLE_PASS ""
#define EXAMPLE_DB "test"

using namespace std;

/**
* Usage example for Driver, Connection, (simple) Statement, ResultSet
*/
int main(int argc, const char **argv)
{
	string url(argc >= 2 ? argv[1] : EXAMPLE_HOST);
	const string user(argc >= 3 ? argv[2] : EXAMPLE_USER);
	const string pass(argc >= 4 ? argv[3] : EXAMPLE_PASS);
	const string database(argc >= 5 ? argv[4] : EXAMPLE_DB);

	cout << endl;
	cout << "Connector/C++ standalone program example..." << endl;
	cout << endl;

	try {
		sql::Driver * driver = get_driver_instance();
		/* Using the Driver to create a connection */
		std::auto_ptr< sql::Connection > con(driver->connect(url, user, pass));
		con->setSchema(database);

		std::auto_ptr< sql::Statement > stmt(con->createStatement());
		std::auto_ptr< sql::ResultSet > res(stmt->executeQuery("SELECT 'Welcome to Connector/C++' AS _message"));
		cout << "\t... running 'SELECT 'Welcome to Connector/C++' AS _message'" << endl;
		while (res->next()) {
			cout << "\t... MySQL replies: " << res->getString("_message") << endl;
			cout << "\t... say it again, MySQL" << endl;
			cout << "\t....MySQL replies: " << res->getString(1) << endl;
		}

	} catch (sql::SQLException &e) {

		cout << "# ERR: SQLException in " << __FILE__;
		cout << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl;
		/* Use what() (derived from std::runtime_error) to fetch the error message */
		cout << "# ERR: " << e.what();
		cout << " (MySQL error code: " << e.getErrorCode();
		cout << ", SQLState: " << e.getSQLState() << " )" << endl;

		return EXIT_FAILURE;
	}

	cout << endl;
	cout << "... find more at http://www,mysql.com" << endl;
	cout << endl;
	return EXIT_SUCCESS;
}

Compiling and running it proves that it does no rocket science. Its a template for you to get started. Hope you will try Connector/C++. The alpha release is around the corner…

nixnutz@ulflinux:~/tmp/trunk> /usr/bin/c++ -o standalone -I/usr/local/include/cppconn/ -Wl,-Bdynamic -lmysqlcppconn examples/standalone_example.cpp
nixnutz@ulflinux:~/tmp/trunk> LD_LIBRARY_PATH=/usr/local/lib/ ./standalone tcp://127.0.0.1 root root

Connector/C++ standalone program example...

        ... running 'SELECT 'Welcome to Connector/C++' AS _message'
        ... MySQL replies: Welcome to Connector/C++
        ... say it again, MySQL
        ....MySQL replies: Welcome to Connector/C++

... find more at http://www.mysql.com

Comments are closed.