MySQL NDB Cluster 8.1 Manual
MySQL NDB Cluster 8.0 Manual
NDB Cluster Internals Manual
This example illustrates basic retrieval of one or more rows
from an NDB
table using the
NdbRecord
interface and an
NdbScanOperation
. We assume
that you have already created and populated the
basic
table, perhaps using the row insertion
example shown previously (see
Section 2.5.1.2, “NDB API Basic Insertion Example”).
You can also find the source code for this example in the file
storage/ndb/ndbapi-examples/ndbapi_basic/ndbapi_basic_read.cpp
.
#include <iostream>
#include <cstdlib>
#include <string>
#include <iterator>
#include <NdbApi.hpp>
class BasicRead
{
public:
BasicRead(const char *connectstring)
: m_connection(connectstring), m_ndb(&m_connection, "ndbapi_examples") {}
bool init();
bool do_read();
private:
Ndb_cluster_connection m_connection;
Ndb m_ndb;
struct BasicRow
{
int attr1, attr2;
};
inline bool on_error(const struct NdbError &error,
const std::string &explanation)
{
// prints error in format:
// ERROR <NdbErrorCode>: <NdbError message>
// explanation what went wrong on higher level (in the example code)
std::cout << "ERROR "<< error.code << ": " << error.message << std::endl;
std::cout << explanation << std::endl;
return false;
}
};
int main(int argc, char **argv)
{
if (argc != 2)
{
std::cout << "Usage: ndb_ndbapi_basic_read <connectstring>" << std::endl;
return EXIT_FAILURE;
}
const char *connectstring = argv[1];
ndb_init();
{
BasicRead example(connectstring);
if (!example.init())
return EXIT_FAILURE;
// Let's verify reads
if (!example.do_read()) return EXIT_FAILURE;
}
ndb_end(0);
return EXIT_SUCCESS;
}
bool BasicRead::do_read()
{
NdbDictionary::Dictionary *dict = m_ndb.getDictionary();
const NdbDictionary::Table *table = dict->getTable("basic");
if (table == nullptr)
return on_error(dict->getNdbError(),
"Cannot access table 'ndbapi_examples.basic'");
// Prepare record specification,
// this will allow us later to access rows in the table
// using our structure BasicRow
NdbRecord* record;
NdbDictionary::RecordSpecification record_spec[] = {
{ table->getColumn("ATTR1"), offsetof(BasicRow, attr1), 0, 0, 0 },
{ table->getColumn("ATTR2"), offsetof(BasicRow, attr2), 0, 0, 0 }
};
record = dict->createRecord(table,
record_spec,
std::size(record_spec),
sizeof(record_spec[0]));
if (record == nullptr)
return on_error(dict->getNdbError(), "Failed to create record");
// All reads will be performed within single transaction
NdbTransaction *transaction = m_ndb.startTransaction(table);
if(transaction == nullptr)
return on_error(m_ndb.getNdbError(), "Failed to start transaction");
// Note the usage of NdbScanOperation instead of regular NdbOperation
NdbScanOperation *operation = transaction->scanTable(record);
if(operation == nullptr)
return on_error(transaction->getNdbError(),
"Failed to start scanTable operation");
// Note the usage of NoCommit flag, as we are only reading the tuples
if (transaction->execute(NdbTransaction::NoCommit) != 0)
return on_error(transaction->getNdbError(),
"Failed to execute transaction");
const BasicRow *row_ptr;
int rc;
std::cout << "ATTR1" << "\t" << "ATTR2" << std::endl;
// Loop over all read results to print them
while ((rc = operation->nextResult(reinterpret_cast<const char **>(&row_ptr),
true, false)) == 0)
std::cout << row_ptr->attr1 << "\t" << row_ptr->attr2
<< std::endl;
if (rc == -1)
return on_error(transaction->getNdbError(), "Failed to read tuple");
operation->close();
m_ndb.closeTransaction(transaction);
dict->releaseRecord(record);
return true;
}
bool BasicRead::init()
{
if (m_connection.connect() != 0)
{
std::cout << "Cannot connect to cluster management server" << std::endl;
return false;
}
if (m_connection.wait_until_ready(30, 0) != 0)
{
std::cout << "Cluster was not ready within 30 secs" << std::endl;
return false;
}
if (m_ndb.init() != 0)
return on_error(m_ndb.getNdbError(), "Failed to initialize ndb object");
return true;
}