Description:
A bug exists between the data accessed and manipulated via the C API (NDB API) and the MySQL CLI. Data queried via the CLI returns missing data in the string e.g. data written via the C API might be "Test String" and the post-update query via the CLI shows "est String". Working the other direction (e.g. updating via the CLI and the querying the data via the C API) shows an upside down question mark preceding the strings.
How to repeat:
Create a test database called testdb via the MySQL CLI. Create a test db using the following instruction:
create table test ( id int not null primary key auto_increment, name varchar(50) not null ) default character set = utf8, engine=ndbcluster;
Insert the following data:
insert into test values (1,'Test 2222');
The result to notice is that there is a space preceding the output string "( Test 2222") instead of "(Test 2222"). Then query the database and observe the result ("set update2222").
Execute this program (using your own connection details), and then query the data via the CLI:
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include "NdbApi.hpp"
#include "mysql.h"
#define PRINT_ERROR(code,msg) \
std::cout << "Error in " << __FILE__ << ", line: " << __LINE__ \
<< ", code: " << code \
<< ", msg: " << msg << "." << std::endl
#define MYSQLERROR(mysql) { \
PRINT_ERROR(mysql_errno(&mysql),mysql_error(&mysql)); \
exit(-1); }
#define APIERROR(error) { \
PRINT_ERROR(error.code,error.message); \
exit(-1); }
struct TestRowdata
{
int32_t id;
char name[50];
};
Ndb_cluster_connection* connect_to_cluster();
void disconnect_from_cluster(Ndb_cluster_connection *c);
Ndb_cluster_connection* connect_to_cluster()
{
Ndb_cluster_connection* c;
if(ndb_init())
exit(EXIT_FAILURE);
c= new Ndb_cluster_connection("192.168.1.135");
if(c->connect(4, 5, 1))
{
fprintf(stderr, "Unable to connect to cluster within 30 seconds.\n\n");
exit(EXIT_FAILURE);
}
if(c->wait_until_ready(30, 0) < 0)
{
fprintf(stderr, "Cluster was not ready within 30 seconds.\n\n");
exit(EXIT_FAILURE);
}
return c;
}
void disconnect_from_cluster(Ndb_cluster_connection *c)
{
delete c;
ndb_end(0);
}
int main(int argc, char* argv[])
{
Ndb_cluster_connection *ndb_connection= connect_to_cluster();
printf("Connection Established.\n\n");
//Execute a test query
Ndb myNdb( ndb_connection, "testdb" );
if (myNdb.init())
APIERROR(myNdb.getNdbError());
NdbDictionary::Dictionary* myDict= myNdb.getDictionary();
const NdbDictionary::Table *myTable= myDict->getTable("test");
NdbTransaction *myTransaction= myNdb.startTransaction();
if (myTransaction == NULL)
APIERROR(myNdb.getNdbError());
NdbDictionary::RecordSpecification recordSpec[2];
const NdbDictionary::Column* pkeyCol = myTable->getColumn("id");
recordSpec[0].column = pkeyCol;
recordSpec[0].offset = offsetof(TestRowdata,id);
recordSpec[0].nullbit_byte_offset = 0;
recordSpec[0].nullbit_bit_in_byte = 0;
const NdbDictionary::Column *pnameCol = myTable->getColumn("name");
recordSpec[1].column = pnameCol;
recordSpec[1].offset = offsetof(TestRowdata,name);
recordSpec[1].nullbit_byte_offset = 0;
recordSpec[1].nullbit_bit_in_byte = 0;
NdbDictionary::RecordSpecification* pkeyRecordSpec = &recordSpec[0];
NdbDictionary::RecordSpecification* nameColRecordSpec = &recordSpec[1];
struct TestRowdata r;
r.id = 1;
struct TestRowdata res;
NdbRecord* pkeyRec = myDict->createRecord( myTable, pkeyRecordSpec /*recordSpec*/, 1, sizeof(NdbDictionary::RecordSpecification) /*sizeof(recordSpec[0])*/ );
NdbRecord* nameRec = myDict->createRecord( myTable, /*nameColRecordSpec*/ recordSpec, 2, /*sizeof(NdbDictionary::RecordSpecification)*/ sizeof(recordSpec[0]) );
const NdbOperation *pop = myTransaction->readTuple(pkeyRec, (char*) &r, nameRec, (char*) &res);
if (pop==NULL)
APIERROR(myTransaction->getNdbError());
if(myTransaction->execute( NdbTransaction::NoCommit ) == -1)
APIERROR(myTransaction->getNdbError());
if( myTransaction->getNdbError().classification == NdbError::NoDataFound )
printf("No data found.\r\n\r\n");
else
printf("Old data: %d - (%s)\r\n\r\n", res.id, res.name);
bzero(&r, sizeof(struct TestRowdata));
bzero(&res, sizeof(struct TestRowdata));
r.id = 1;
char msg[] = "Test update2222";
strncpy( res.name, msg, sizeof( msg ) );
const NdbOperation* updateOp =myTransaction->updateTuple( pkeyRec, (char*) &r, nameRec, (char*) &res );
if( updateOp == NULL )
APIERROR(myTransaction->getNdbError());
if(myTransaction->execute( NdbTransaction::Commit ) == -1)
APIERROR(myTransaction->getNdbError());
myTransaction->close();
disconnect_from_cluster(ndb_connection);
return EXIT_SUCCESS;
}
Suggested fix:
I am not sure of the fix but a work-around would to be to exclusively use one API over the other to access the data in the database.