Documentation Home
MySQL NDB Cluster API Developer Guide
Download this Manual
PDF (US Ltr) - 3.5Mb
PDF (A4) - 3.5Mb


MySQL NDB Cluster API Developer Guide  /  ...  /  NDB API Basic Reading Example

2.5.1.3 NDB API Basic Reading Example

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;
}