MySQL Connector/C++  8.0.6
MySQL connector library for C and C++ applications
Connector/C++ 8.0 X DevAPI Reference

Connector/C++ 8.0 implements the X DevAPI, as described in the X DevAPI User Guide. The X DevAPI allows one to work with MySQL Servers implementing a document store via the X Plugin. One can also execute plain SQL queries using this API.

To get started, check out some of the main X DevAPI classes:

A more complete example of code that access MySQL Document Store using the X DevAPI is presented below. See also the list of X DevAPI classes.

Sample code which uses Connector/C++ with X DevAPI

The following Connector/C++ application connects to a MySQL Server with X Plugin, creates a document collection, adds a few documents to it, queries the collection and displays the result. The sample code can be found in file testapp/devapi_test.cc in the source distribution of Connector/C++ 8.0. See Using Connector/C++ 8.0 for instructions on how to build the sample code.

Code which uses X DevAPI should include the mysql_devapi.h header. The API is declared within the mysqlx namespace:

#include <mysql_devapi.h>
using ::std::cout;
using ::std::endl;
using namespace ::mysqlx;

To create an Session object, specify DNS name of a MySQL Server, the port on which the plugin listens (default port is 33060) and user credentials:

int main(int argc, const char* argv[])
try {
unsigned short port = (argc > 1 ? atoi(argv[1]) : 0);
const char *user = (argc > 2 ? argv[2] : "root");
const char *pwd = (argc > 3 ? argv[3] : NULL);
if (0 == port)
{
// Default MySQL X port
port = 33060;
}
cout << "Creating session on localhost, port " << port
<< " ..." << endl;
Session sess("localhost", port, user, pwd);

Another way of specifying session parameters is by means of a mysqlx connection string like "mysqlx://mike:s3cr3t!@localhost:13009". Once created, the session is ready to be used. If the session can not be established, the Session constructor throws an error.

To manipulate documents in a collection, create a Collection object, first asking session for that collection's Schema:

cout <<"Session accepted, creating collection..." <<endl;
Schema sch= sess.getSchema("test");
Collection coll= sch.createCollection("c1", true);

The true parameter to createCollection() method specifies that collection should be re-used if it already exists. Without this parameter an attempt to create an already existing collection produces an error. It is also possible to create a Collection object directly, without creating the Schema instance:

Collection coll = sess.getSchema("test").getCollection("c1",true)

Before adding documents to the collection, all the existing documents are removed first using the Collection::remove() method (expression "true" selects all documents in the collection):

coll.remove("true").execute();

Note that the remove() method returns an operation that must be explicitly executed to take effect. When executed, operation returns a result (ignored here; the results are used later).

To insert documents use the Collection::add() method. Documents are described by JSON strings using the same syntax as MySQL Server. Note that double quotes are required around field names and they must be escaped inside C strings, unless the new C++11 R"(...)" string literal syntax is used as in the example below:

{
Result add;
add= coll.add(R"({ "name": "foo", "age": 1 })").execute();
cout <<"- added doc with id: " <<add.getDocumentId() <<endl;
add= coll.add(R"({ "name": "bar", "age": 2, "toys": [ "car", "ball" ] })")
.execute();
cout <<"- added doc with id: " <<add.getDocumentId() <<endl;
add= coll.add(R"({
"name": "baz",
"age": 3,
"date": { "day": 20, "month": "Apr" }
})").execute();
cout <<"- added doc with id: " <<add.getDocumentId() <<endl;
add= coll.add(R"({ "_id": "myuuid-1", "name": "foo", "age": 7 })")
.execute();
cout <<"- added doc with id: " <<add.getDocumentId() <<endl;
}

Result of the add() operation is stored in the add variable to be able to read identifiers of the documents that were added. These identifiers are generated by the connector, unless an added document contains an "_id" field which specifies its identifier. Note how internal code block is used to delete the result when it is no longer needed.

Note
It is possible to chain several add() calls as follows: coll.add(doc1).add(doc2)...add(docN).execute(). It is also possible to pass several documents to a single add() call: coll.add(doc1, ..., docN).execute(). Another option is to pass to Collection::add() an STL container with several documents.

To query documents of a collection use the Collection::find() method:

DocResult docs = coll.find("age > 1 and name like 'ba%'").execute();

The result of the find() operation is stored in a variable of type DocResult which gives access to the returned documents that satisfy the selection criteria. These documents can be fetched one by one using the DocResult::fetchOne() method, until it returns a null document that signals end of the sequence:

DbDoc doc = docs.fetchOne();
for (int i = 0; doc; ++i, doc = docs.fetchOne())
{
cout <<"doc#" <<i <<": " <<doc <<endl;

Given a DbDoc object it is possible to iterate over its fields as follows:

for (Field fld : doc)
{
cout << " field `" << fld << "`: " <<doc[fld] << endl;
}

Note how the operator[] is used to access values of document fields:

string name = doc["name"];
cout << " name: " << name << endl;

The value of a field is automatically converted to a corresponding C++ type. If the C++ type does not match the type of the field value, conversion error is thrown.

Fields which are sub-documents can be converted to the DbDoc type. The following code demonstrates how to process a "date" field which is a sub-document. Note how methods DbDoc::hasField() and DbDoc::fieldType() are used to examine existence and type of a field within a document.

if (doc.hasField("date") && Value::DOCUMENT == doc.fieldType("date"))
{
cout << "- date field" << endl;
DbDoc date = doc["date"];
for (Field fld : date)
{
cout << " date `" << fld << "`: " << date[fld] << endl;
}
string month = doc["date"]["month"];
int day = date["day"];
cout << " month: " << month << endl;
cout << " day: " << day << endl;
}

In case of arrays, currently no conversion to C++ types is defined. However, individual elements of an array value can be accessed using operator[] or they can be iterated using range for loop.

if (doc.hasField("toys") && Value::ARRAY == doc.fieldType("toys"))
{
cout << "- toys:" << endl;
for (auto toy : doc["toys"])
{
cout << " " << toy << endl;
}
}

Any errors thrown by Connector/C++ derive from the mysqlx::Error type and can be processed as follows:

catch (const mysqlx::Error &err)
{
cout <<"ERROR: " <<err <<endl;
return 1;
}

The complete code of the example is presented below:

/*
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
*
* The MySQL Connector/C++ is licensed under the terms of the GPLv2
* <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
* MySQL Connectors. There are special exceptions to the terms and
* conditions of the GPLv2 as it is applied to this software, see the
* FLOSS License Exception
* <http://www.mysql.com/about/legal/licensing/foss-exception.html>.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <iostream>
#include <mysql_devapi.h>
using ::std::cout;
using ::std::endl;
using namespace ::mysqlx;
int main(int argc, const char* argv[])
try {
unsigned short port = (argc > 1 ? atoi(argv[1]) : 0);
const char *user = (argc > 2 ? argv[2] : "root");
const char *pwd = (argc > 3 ? argv[3] : NULL);
if (0 == port)
{
// Default MySQL X port
port = 33060;
}
cout << "Creating session on localhost, port " << port
<< " ..." << endl;
Session sess("localhost", port, user, pwd);
cout <<"Session accepted, creating collection..." <<endl;
Schema sch= sess.getSchema("test");
Collection coll= sch.createCollection("c1", true);
cout <<"Inserting documents..." <<endl;
coll.remove("true").execute();
{
Result add;
add= coll.add(R"({ "name": "foo", "age": 1 })").execute();
cout <<"- added doc with id: " <<add.getDocumentId() <<endl;
add= coll.add(R"({ "name": "bar", "age": 2, "toys": [ "car", "ball" ] })")
.execute();
cout <<"- added doc with id: " <<add.getDocumentId() <<endl;
add= coll.add(R"({
"name": "baz",
"age": 3,
"date": { "day": 20, "month": "Apr" }
})").execute();
cout <<"- added doc with id: " <<add.getDocumentId() <<endl;
add= coll.add(R"({ "_id": "myuuid-1", "name": "foo", "age": 7 })")
.execute();
cout <<"- added doc with id: " <<add.getDocumentId() <<endl;
}
cout <<"Fetching documents..." <<endl;
DocResult docs = coll.find("age > 1 and name like 'ba%'").execute();
DbDoc doc = docs.fetchOne();
for (int i = 0; doc; ++i, doc = docs.fetchOne())
{
cout <<"doc#" <<i <<": " <<doc <<endl;
for (Field fld : doc)
{
cout << " field `" << fld << "`: " <<doc[fld] << endl;
}
string name = doc["name"];
cout << " name: " << name << endl;
if (doc.hasField("date") && Value::DOCUMENT == doc.fieldType("date"))
{
cout << "- date field" << endl;
DbDoc date = doc["date"];
for (Field fld : date)
{
cout << " date `" << fld << "`: " << date[fld] << endl;
}
string month = doc["date"]["month"];
int day = date["day"];
cout << " month: " << month << endl;
cout << " day: " << day << endl;
}
if (doc.hasField("toys") && Value::ARRAY == doc.fieldType("toys"))
{
cout << "- toys:" << endl;
for (auto toy : doc["toys"])
{
cout << " " << toy << endl;
}
}
cout << endl;
}
cout <<"Done!" <<endl;
}
catch (const mysqlx::Error &err)
{
cout <<"ERROR: " <<err <<endl;
return 1;
}
catch (std::exception &ex)
{
cout <<"STD EXCEPTION: " <<ex.what() <<endl;
return 1;
}
catch (const char *ex)
{
cout <<"EXCEPTION: " <<ex <<endl;
return 1;
}

A sample output produced by this code:

Creating session on localhost, port 13009 ...
Session accepted, creating collection...
Inserting documents...
- added doc with id: AA71B4BF6B72E511BD76001E684A06F0
- added doc with id: 2885B4BF6B72E511BD76001E684A06F0
- added doc with id: 3492B4BF6B72E511BD76001E684A06F0
- added doc with id: myuuid-1
Fetching documents...
doc#0: {"_id": "AEFD9C44EB77E5116134001E684A06F0", "age": 3, "date": {"day": 20, "month": "Apr"}, "name": "baz"}
field `_id`: AEFD9C44EB77E5116134001E684A06F0
field `age`: 3
field `date`: <document>
field `name`: baz
name: baz
- date field
date `day`: 20
date `month`: Apr
month: Apr
day: 20
doc#1: {"_id": "A0ABC08DAABAD1110C120800273BD115", "age": 2, "name": "bar", "toys": ["car", "ball"]}
field `_id`: A0ABC08DAABAD1110C120800273BD115
field `age`: 2
field `name`: bar
field `toys`: <array with 2 element(s)>
name: bar
- toys:
car
ball
Done!