How to Connect C++ Programs to MariaDB
Today, we announced the general availability of MariaDB Connector/C++. The C++ language is known for its efficiency, versatility and extensibility. In fact, it’s often used in industries like fintech and gaming where applications require predictable concurrency and latency. With MariaDB Connector/C++, developers can use the new connector within their applications to natively connect to MariaDB Server on premises and in the cloud on MariaDB SkySQL.
In this article I’ll be introducing you to MariaDB Connector/C++ with simple examples that demonstrate create, read, update, and delete (CRUD) interactions with data stored in MariaDB. More specifically, I’m going to walk through the process of creating a C++ console application that will allow you to perform simple operations for managing tasks. But enough talk, let’s get started!
Downloading and Installing
In order to use MariaDB Connector/C++ you need to have access to an instance of MariaDB Server. There are a variety of ways you can get started with MariaDB on your local machine, on-premises, or even in the cloud.
- Download and install MariaDB Community Server
- Download and install MariaDB Enterprise Server
- Deploy with MariaDB SkySQL, the ultimate MariaDB cloud database
After you’ve set up a MariaDB Server instance you can follow the steps provided within the MariaDB Enterprise documentation for instructions on how to download and install MariaDB Connector/C++.
Preparing MariaDB Server
In this example, before you can use the new MariaDB C++ connector you will need to have a database and table. Using a client of your choosing, connect to your MariaDB database instance and:
1. Create a new database and a single table that will be responsible for storing the task records.
CREATE DATABASE IF NOT EXISTS todo; CREATE TABLE todo.tasks ( id INT(11) unsigned NOT NULL AUTO_INCREMENT, description VARCHAR(500) NOT NULL, completed BOOLEAN NOT NULL DEFAULT 0, PRIMARY KEY (id) );
2. Create a new database user that Connector/C++ will use to connect to MariaDB.
CREATE USER IF NOT EXISTS app_user@localhost IDENTIFIED BY 'Password123!'; GRANT ALL PRIVILEGES ON todo.* TO app_user@localhost;
Connecting to MariaDB Server
Now that you have your database instance, schema, and user set up, it’s time to jump into C++. It all starts by establishing a connection to MariaDB. Of course, to do that, you need to have included the MariaDB connector header files, specifically conncpp.hpp, at the top of the file that you’re adding your C++ code to.
#include <mariadb/conncpp.hpp>
To establish a connection, start by retrieving a Driver
object that can then be used, in combination with Java Database Connectivity (JDBC) configuration information, to obtain a Connection
object.
// Instantiate Driver sql::Driver* driver = sql::mariadb::get_driver_instance(); // Configure Connection sql::SQLString url("jdbc:mariadb://localhost:3306/todo"); sql::Properties properties({{"user", "app_user"}, {"password", "Password123!"}}); // Establish Connection std::unique_ptr<sql::Connection> conn(driver->connect(url, properties));
For more information on MariaDB’s Connector/C++’s connection functionality be sure to check out our official enterprise documentation.
Adding Tasks
Once you’ve obtained a Connection
object, you’re off to the races! Using conn, from the previous section, you’re now able to execute SQL through the use of a prepared statement to insert data into MariaDB.
// Create a new PreparedStatement std::unique_ptr<sql::PreparedStatement> stmnt(conn->prepareStatement("insert into tasks (description) values (?)")); // Bind values to SQL statement stmnt->setString(1, description); // Execute query stmnt->executeQuery();
Retrieving Tasks
Using a very similar approach, as within the last section, you can also create a Statement
object to retrieve and print out all of the task records within the tasks table.
// Create a new Statement std::unique_ptr stmnt(conn->createStatement()); // Execute query sql::ResultSet *res = stmnt->executeQuery("select * from tasks"); // Loop through and print results while (res->next()) { std::cout << "id = " << res->getInt(1); std::cout << ", description = " << res->getString(2); std::cout << ", completed = " << res->getBoolean(3) << "\n"; }
Updating Tasks
You can also use a PreparedStatement
and specifying parameters (and values) to locate and modify an existing task record.
// Create a new PreparedStatement std::unique_ptr stmnt(conn->prepareStatement("update tasks set completed = ? where id = ?")); // Bind values to SQL statement stmnt->setBoolean(1, completed); stmnt->setInt(2, id); // Execute query stmnt->executeQuery();
Deleting Tasks
And, of course, you also have the ability to remove data from MariaDB by using a DELETE SQL
statement with a PreparedStatement
, to target a specific record.
// Create a new PreparedStatement std::unique_ptr stmnt(conn->prepareStatement("delete from tasks where id = ?")); // Bind values to SQL statement stmnt->setInt(1, id); // Execute query stmnt->executeQuery();
Bringing It All Together
Finally, you can put everything together in one, self-contained example by copying and pasting the code below into a new file called tasks.cpp. The sample below combines all of the CRUD operations I’ve gone through into a collection of functions that can be executed from the main method.
#include <iostream> #include <cstring> #include <mariadb/conncpp.hpp> // Delete a task record (indicated by id) void deleteTask(std::unique_ptr &conn, int id) { try { // Create a new PreparedStatement std::unique_ptr stmnt(conn->prepareStatement("delete from tasks where id = ?")); // Bind values to SQL statement stmnt->setInt(1, id); // Execute query stmnt->executeQuery(); } catch(sql::SQLException& e){ std::cerr << "Error deleting task: " << e.what() << std::endl; } } // Update the completed value of a task record (indicated by id) void updateTaskStatus(std::unique_ptr &conn, int id, bool completed) { try { // Create a new PreparedStatement std::unique_ptr stmnt(conn->prepareStatement("update tasks set completed = ? where id = ?")); // Bind values to SQL statement stmnt->setBoolean(1, completed); stmnt->setInt(2, id); // Execute query stmnt->executeQuery(); } catch(sql::SQLException& e){ std::cerr << "Error updating task status: " << e.what() << std::endl; } } // Create a new task record void addTask(std::unique_ptr &conn, std::string description) { try { // Create a new PreparedStatement std::unique_ptr stmnt(conn->prepareStatement("insert into tasks (description) values (?)")); // Bind values to SQL statement stmnt->setString(1, description); // Execute query stmnt->executeQuery(); } catch(sql::SQLException& e){ std::cerr << "Error inserting new task: " << e.what() << std::endl; } } // Print all records in tasks table void showTasks(std::unique_ptr &conn) { try { // Create a new Statement std::unique_ptr stmnt(conn->createStatement()); // Execute query sql::ResultSet *res = stmnt->executeQuery("select * from tasks"); // Loop through and print results while (res->next()) { std::cout << "id = " << res->getInt(1); std::cout << ", description = " << res->getString(2); std::cout << ", completed = " << res->getBoolean(3) << "\n"; } } catch(sql::SQLException& e){ std::cerr << "Error selecting tasks: " << e.what() << std::endl; } } // Main Process int main(int argc, char **argv){ if (argc==1){ std::cout << "Please provide an argument.\n"; } else { try { // Instantiate Driver sql::Driver* driver = sql::mariadb::get_driver_instance(); // Configure Connection sql::SQLString url("jdbc:mariadb://localhost:3306/todo"); sql::Properties properties({{"user", "app_user"}, {"password", "Password123!"}}); // Establish Connection std::unique_ptr conn(driver->connect(url, properties)); // Use arguments to determine execution next steps if (!strcmp(argv[1],"showTasks")) { showTasks(conn); } else if (!strcmp(argv[1],"addTask")) { if (argc != 3) { std::cout << "Invalid arguments"; return 1; } addTask(conn, argv[2]); } else if (!strcmp(argv[1],"updateTaskStatus")) { if (argc != 4) { std::cout << "Invalid arguments"; return 1; } updateTaskStatus(conn, atoi(argv[2]), argv[3]); } else if (!strcmp(argv[1],"deleteTask")) { if (argc != 3) { std::cout << "Invalid arguments"; return 1; } deleteTask(conn, atoi(argv[2])); } // Close Connection conn->close(); } catch(sql::SQLException& e){ std::cerr << "Error Connecting to MariaDB Platform: " << e.what() << std::endl; // Exit (Failed) return 1; } } // Exit (Success) return 0; }
You can also find the full source of this sample application here. The source for this C++ example is contained within a repository for an application called “TODO”, which also includes a web front-end and several other MariaDB connector integration sample applications spanning a multitude of languages.
Running the Application
Within a Linux environment, after you’ve created tasks.cpp, you can build an executable file, called tasks, using a C++ compiler.
$ g++ -o tasks tasks.cpp -std=c++11 -lmariadbcpp
Using the executable file you can supply various argument values to test the CRUD operations.
- Inserting a new task record by supplying a value for description.
./tasks addTask ‘A New Task’
- Printing out all task records.
./tasks showTasks
- Updating a task record’s completed value. Simply supply values for id and completed.
./tasks updateTaskStatus 1 1
- Delete a task record by supplying an id value.
./tasks deleteTask 1
Just the Beginning
Hopefully, you enjoyed seeing how easy it is to get started using C++ with MariaDB. While this is a great introduction to C++ programming with MariaDB, we’ve only started to scratch the surface of what’s possible!
Looking to dive deeper into MariaDB Connector/C++? Be sure to check out the MariaDB Developer Hub for even more content on the new C++ connector as well as many other MariaDB features and capabilities.