/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
#include <NdbOut.hpp>
#include <NdbApi.hpp>
#include <NdbSleep.h>
#include <NDBT.hpp>
#include <NdbError.hpp>

static Ndb_cluster_connection *g_cluster_connection= 0;
static Ndb* g_ndb = 0;
static const char* g_tablename1 = "T_DEF1"; //The normal table with default values
static const char* g_tablename2 = "T_DEF2"; //The table for Test that maximum length defaults work
//The table for Test that an attempt to insert to a table containing defaults 
//without supplying a value for a not-null, non-defaulted column still fails
static const char* g_tablename3 = "T_DEF3"; 
static NdbDictionary::Dictionary* g_dict = 0;
static const unsigned int column_count_table1 = 8;
static const unsigned int column_count_table2 = 2;
static const unsigned int column_count_table3 = 2;

static struct NdbError g_ndberror;
static int create_table();

static bool
connect_ndb()
{
  g_cluster_connection = new Ndb_cluster_connection();
  if(g_cluster_connection->connect(12, 5, 1) != 0)
    return false;

  g_ndb = new Ndb(g_cluster_connection, "TEST");
  g_ndb->init();
  if(g_ndb->waitUntilReady(30) != 0)
    return false;

  return true;
}

static void
disconnect_ndb()                                            {
  delete g_ndb;
  delete g_cluster_connection;
  g_ndb = 0;
//  g_table = 0;
  g_cluster_connection= 0;
}

#define PRINT_ERROR(error) \
   ndbout << "Error in " << __FILE__ << ", line: " << __LINE__ \
            << ", code: " << error.code \
            << ", msg: " << error.message << "." << endl
#define FAIL(error_msg) \
  ndbout << error_msg << " at line " << __LINE__ << endl; \
  return NDBT_FAILED

static const int            tab1_c1_default= 6; 
static const float          tab1_c2_default= float(1234.56);
static const double         tab1_c3_default= 4567.89;
static const char           tab1_c4_default[]= "aaaaaa      ";
static const unsigned int   tab1_c4_default_siglen= 12;
static const char           tab1_c5_default[]= "\x6" "aaaaaa\0\0\0\0";
static const unsigned int   tab1_c5_default_siglen= 7;
static const char           tab1_c6_default[]= "aaaaaa      ";
static const unsigned int   tab1_c6_default_siglen= 0;
static const char           tab1_c7_default[]= "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
static const char           tab1_c7_default_siglen= 1;

static const int            tab2_c1_default_len= 8052 - 4 - 2;
/* Max row length minus 4 bytes for key, minus 2 bytes for length info */
static const char           tab2_c1_default_char= 'V';

static int 
create_table()
{
  g_dict = g_ndb->getDictionary();
  if ((g_dict->getTable(g_tablename1) != 0) &&
      (g_dict->dropTable(g_tablename1) != 0))
  {
    PRINT_ERROR(g_dict->getNdbError());
    return NDBT_FAILED;
  }

  if ((g_dict->getTable(g_tablename2) != 0) &&
      (g_dict->dropTable(g_tablename2) != 0))
  {
    PRINT_ERROR(g_dict->getNdbError());
    return NDBT_FAILED;
  }

  if ((g_dict->getTable(g_tablename3) != 0) &&
      (g_dict->dropTable(g_tablename3) != 0))
  {
    PRINT_ERROR(g_dict->getNdbError());
    return NDBT_FAILED;
  }

  NdbDictionary::Table tab(g_tablename1);
  tab.setLogging(false);
  
  NdbDictionary::Table tab2(g_tablename2);
  tab2.setLogging(false);

  NdbDictionary::Table tab3(g_tablename3);
  tab3.setLogging(false);

  // col PK - Uint32
  { NdbDictionary::Column col("PK");
    col.setType(NdbDictionary::Column::Unsigned);
    col.setPrimaryKey(true);
    col.setNullable(FALSE);
    col.setAutoIncrement(TRUE);
    col.setDefaultValue(NULL);
    tab.addColumn(col);
  }
 
  { 
    NdbDictionary::Column col("C1");
    col.setType(NdbDictionary::Column::Int);
    col.setDefaultValue(&tab1_c1_default,sizeof(int));
    tab.addColumn(col);
  }
  
  { 
    NdbDictionary::Column col("C2");
    col.setType(NdbDictionary::Column::Float);
    col.setDefaultValue(&tab1_c2_default, sizeof(float));
    tab.addColumn(col);
  }

  { 
    NdbDictionary::Column col("C3");
    col.setType(NdbDictionary::Column::Double);
    col.setDefaultValue(&tab1_c3_default, sizeof(double));
    tab.addColumn(col);
  }

  { 
    NdbDictionary::Column col("C4");
    col.setType(NdbDictionary::Column::Char);
    col.setLength(12);
    col.setDefaultValue(tab1_c4_default, 12);
    tab.addColumn(col);
  }

  { 
    NdbDictionary::Column col("C5");
    col.setType(NdbDictionary::Column::Varchar);
    col.setLength(199);
    col.setDefaultValue(tab1_c5_default, tab1_c5_default_siglen);
    tab.addColumn(col);
  }


  { 
    /* Test non-null pointer passed, but with zero length? */
    NdbDictionary::Column col("C6");
    col.setType(NdbDictionary::Column::Char);
    col.setLength(12);
    col.setNullable(TRUE);
    col.setDefaultValue(tab1_c6_default, tab1_c6_default_siglen);
    tab.addColumn(col);
  }

  //Test that a zero-length VARCHAR default works
  { 
    NdbDictionary::Column col("C7");
    col.setType(NdbDictionary::Column::Varchar);
    col.setLength(10);
    col.setDefaultValue(tab1_c7_default, tab1_c7_default_siglen);
    tab.addColumn(col);
  }

  //create table T_DEF2
  { NdbDictionary::Column col("PK");
    col.setType(NdbDictionary::Column::Unsigned);
    col.setPrimaryKey(true);
    col.setNullable(FALSE);
    col.setAutoIncrement(FALSE);
    col.setDefaultValue(NULL, 0);
    tab2.addColumn(col);
  }

  //Test that maximum length defaults work
  { 
    char default_data[tab2_c1_default_len + 2];
    default_data[0] = (tab2_c1_default_len >> 0) & 0xff;
    default_data[1] = (tab2_c1_default_len >> 8) & 0xff;
    memset(default_data + 2, tab2_c1_default_char, tab2_c1_default_len);
    NdbDictionary::Column col("C1");
    col.setType(NdbDictionary::Column::Longvarchar);
    col.setLength(tab2_c1_default_len);
    col.setDefaultValue(default_data, tab2_c1_default_len + 2);
    tab2.addColumn(col);
  }

  //Create table T_DEF3
  { NdbDictionary::Column col("PK");
    col.setType(NdbDictionary::Column::Unsigned);
    col.setPrimaryKey(true);
    col.setNullable(FALSE);
    col.setAutoIncrement(FALSE);
    col.setDefaultValue(NULL, 0);
    tab3.addColumn(col);
  }

  //For column without supplying a value for a not-null, non-defaulted column
  { NdbDictionary::Column col("C1");
    col.setType(NdbDictionary::Column::Unsigned);
    col.setNullable(FALSE);
    col.setDefaultValue(NULL, 0);
    tab3.addColumn(col);
  }
  
  // create table
  if(g_dict->createTable(tab) != 0)
  {
    PRINT_ERROR(g_dict->getNdbError());
    return NDBT_FAILED;
  }

  if(g_dict->createTable(tab2) != 0)
  {
    PRINT_ERROR(g_dict->getNdbError());
    return NDBT_FAILED;
  }

  if(g_dict->createTable(tab3) != 0)
  {
    PRINT_ERROR(g_dict->getNdbError());
    return NDBT_FAILED;
  }

  return NDBT_OK;
}

static int
ndb_error_check(const struct NdbError& error, unsigned int line)
{
  if (error.code != 850)
  {
    PRINT_ERROR(error);
    ndbout << " at line " << line << "\n";
    return NDBT_FAILED;
  }
  return NDBT_OK;
}

#define CHECK_ERROR(error) {                           \
  if (ndb_error_check(error, __LINE__) == NDBT_FAILED) \
    return NDBT_FAILED;                                \
  }

static int
create_table_error()
{
  g_dict = g_ndb->getDictionary();

  /*
   * 1. The following test case is for fixed columns that
   *    there are too long or too short default values.
   */
  //for too long default value
  NdbDictionary::Table tab1("T_DEF_TEST1");
  tab1.setLogging(false);

  { NdbDictionary::Column col("PK");
    col.setType(NdbDictionary::Column::Unsigned);
    col.setPrimaryKey(true);
    col.setNullable(FALSE);
    col.setDefaultValue(NULL);
    tab1.addColumn(col);
  }

  { int default_data = 6;
    NdbDictionary::Column col("C1");
    col.setType(NdbDictionary::Column::Int);
    col.setDefaultValue(&default_data, 8);
    tab1.addColumn(col);
  }

  if(g_dict->createTable(tab1) != 0)
  {
    CHECK_ERROR(g_dict->getNdbError());
  }
  else
  {
    FAIL("Create table should not have succeeded");
  }
  
  //for too short default value
  NdbDictionary::Table tab2("T_DEF_TEST2");
  tab2.setLogging(false);

  { NdbDictionary::Column col("PK");
    col.setType(NdbDictionary::Column::Unsigned);
    col.setPrimaryKey(true);
    col.setNullable(FALSE);
    col.setAutoIncrement(TRUE);
    col.setDefaultValue(NULL);
    tab2.addColumn(col);
  }

  { const char default_data[] = "aaaaaa";
    NdbDictionary::Column col("C4");
    col.setType(NdbDictionary::Column::Char);
    col.setLength(12);
    col.setDefaultValue(default_data, 6);
    tab2.addColumn(col);
  }

  if(g_dict->createTable(tab2) != 0)
  {
    CHECK_ERROR(g_dict->getNdbError());
  }
  else
  {
    FAIL("Create table should not have succeeded");
  }

  /*
   * 2. The following test case is for Var-type columns that
   *    there are too long default values.
   */
  NdbDictionary::Table tab3("T_DEF_TEST3");
  tab3.setLogging(false);

  { NdbDictionary::Column col("PK");
    col.setType(NdbDictionary::Column::Unsigned);
    col.setPrimaryKey(true);
    col.setNullable(FALSE);
    col.setAutoIncrement(TRUE);
    col.setDefaultValue(NULL);
    tab3.addColumn(col);
  }

  { char default_data[20];
    memset(default_data, 0, 20);
    Uint8 * p = (Uint8*)default_data;
    *p = 10;
    memcpy(default_data + 1, "aaaaaaaaaa", 10);
    NdbDictionary::Column col("C5");
    col.setType(NdbDictionary::Column::Varchar);
    col.setLength(9);
    col.setDefaultValue(default_data, 11);
    tab3.addColumn(col);
  }

  if(g_dict->createTable(tab3) != 0)
  {
    CHECK_ERROR(g_dict->getNdbError());
  }
  else
  {
    FAIL("Create table should not have succeeded");
  }


  /*
   * 3. Test attempt to set default value for primary key
   */
  NdbDictionary::Table tab4("T_DEF_TEST4");
  tab4.setLogging(false);

  { NdbDictionary::Column col("PK");
    unsigned int default_val=22;
    col.setType(NdbDictionary::Column::Unsigned);
    col.setPrimaryKey(true);
    col.setNullable(FALSE);
    col.setAutoIncrement(TRUE);
    col.setDefaultValue(&default_val, sizeof(default_val));
    tab4.addColumn(col);
  }

  if(g_dict->createTable(tab4) == 0)
  {
    FAIL("Create table should not have succeeded");
  }

  if(g_dict->getNdbError().code != 792)
  {
    PRINT_ERROR(g_dict->getNdbError());
    return NDBT_FAILED;
  }
 
  /*
   * 4. The following test case is for Var-type columns that
   *    there are too long default values, where the passed
   *    value is short, but the implied value is too long
   */
  NdbDictionary::Table tab5("T_DEF_TEST5");
  tab5.setLogging(false);

  { NdbDictionary::Column col("PK");
    col.setType(NdbDictionary::Column::Unsigned);
    col.setPrimaryKey(true);
    col.setNullable(FALSE);
    col.setAutoIncrement(TRUE);
    col.setDefaultValue(NULL);
    tab5.addColumn(col);
  }

  { char default_data[20];
    memset(default_data, 0, 20);
    Uint8 * p = (Uint8*)default_data;
    *p = 15;
    memcpy(default_data + 1, "aaaaaaaaaa", 15);
    NdbDictionary::Column col("C5");
    col.setType(NdbDictionary::Column::Varchar);
    col.setLength(9);
    /* Within range, but contained VARCHAR is too long */
    col.setDefaultValue(default_data, 10);
    tab5.addColumn(col);
  }

  if(g_dict->createTable(tab5) != 0)
  {
    CHECK_ERROR(g_dict->getNdbError());
  }
  else
  {
    FAIL("Create table should not have succeeded");
  }

  return NDBT_OK;
}

static int 
drop_table()
{
  if ((g_dict != 0) && ( g_dict->getTable(g_tablename1) != 0))
  {
    if(g_dict->dropTable(g_tablename1))
      PRINT_ERROR(g_dict->getNdbError());
  }

  if ((g_dict != 0) && ( g_dict->getTable(g_tablename2) != 0))
  {
    if(g_dict->dropTable(g_tablename2))
      PRINT_ERROR(g_dict->getNdbError());
  }

  if ((g_dict != 0) && ( g_dict->getTable(g_tablename3) != 0))
  {
    if(g_dict->dropTable(g_tablename3))
      PRINT_ERROR(g_dict->getNdbError());
  }

  return NDBT_OK;
}

static int do_insert()
{
  const NdbDictionary::Table *myTable= g_dict->getTable(g_tablename1);

  if (myTable == NULL)
  {
    PRINT_ERROR(g_dict->getNdbError());
    return NDBT_FAILED; 
  }

  NdbTransaction *myTransaction= g_ndb->startTransaction(); 
  if (myTransaction == NULL)
  {
    PRINT_ERROR(g_ndb->getNdbError());
    return NDBT_FAILED;
  }

  NdbOperation *myOperation= myTransaction->getNdbOperation(myTable);
  NdbOperation *myOperation1= myTransaction->getNdbOperation(myTable); 
  if (myOperation == NULL || myOperation1 == NULL) 
  {
    PRINT_ERROR(myTransaction->getNdbError());
    g_ndb->closeTransaction(myTransaction);
    return NDBT_FAILED;
  }

  myOperation->insertTuple();
  myOperation->equal("PK", 1);
  myOperation1->insertTuple();
  myOperation1->equal("PK", 2);

  //insert the second table T_DEF2
  const NdbDictionary::Table *myTable2= g_dict->getTable(g_tablename2);

  if (myTable == NULL)
  {
    PRINT_ERROR(g_dict->getNdbError());
    return NDBT_FAILED;
  }
  NdbOperation *myOperation2 = myTransaction->getNdbOperation(myTable2);
  if (myOperation2 == NULL)
  {
    PRINT_ERROR(myTransaction->getNdbError());
    g_ndb->closeTransaction(myTransaction);
    return NDBT_FAILED;
  }

  myOperation2->insertTuple();
  myOperation2->equal("PK", 1);


  /* Test insert of max length tuple with max length default
   * Could theoretically expose kernel overflow with default 
   * + supplied value
   */
  myOperation2=myTransaction->getNdbOperation(myTable2);
  if (myOperation2 == NULL)
  {
    PRINT_ERROR(myTransaction->getNdbError());
    g_ndb->closeTransaction(myTransaction);
    return NDBT_FAILED;
  }
  
  myOperation2->insertTuple();
  myOperation2->equal("PK", 2);

  {
    char default_data[tab2_c1_default_len + 2];
    default_data[0] = (tab2_c1_default_len >> 0) & 0xff;
    default_data[1] = (tab2_c1_default_len >> 8) & 0xff;
    memset(default_data + 2, tab2_c1_default_char, tab2_c1_default_len);
    
    myOperation2->setValue("C1", default_data);
  }

  if (myTransaction->execute(NdbTransaction::Commit) == -1)
  {
    PRINT_ERROR(myTransaction->getNdbError());
    g_ndb->closeTransaction(myTransaction);
    return NDBT_FAILED;
  }
  
  g_ndb->closeTransaction(myTransaction);

  //The following insert should fail, and return error code
  const NdbDictionary::Table *myTable3= g_dict->getTable(g_tablename3);

  if (myTable3 == NULL)
  {
    PRINT_ERROR(g_dict->getNdbError());
    return NDBT_FAILED;
  }

  NdbTransaction *myTransaction3 = g_ndb->startTransaction();
  if (myTransaction3 == NULL)
  {
    PRINT_ERROR(g_ndb->getNdbError());
    return NDBT_FAILED;
  }

  NdbOperation *myOperation3 = myTransaction3->getNdbOperation(myTable3);
  if (myOperation3 == NULL)
  {
    PRINT_ERROR(myTransaction3->getNdbError());
    g_ndb->closeTransaction(myTransaction3);
    return NDBT_FAILED;
  }
  myOperation3->insertTuple();
  myOperation3->equal("PK", 1);

  /* It should return error code 839 ( msg: Illegal null attribute)
   * for an attempt to insert to a table containing defaults 
   * without supplying a value for a not-null, non-defaulted column
  */
  if (myTransaction3->execute(NdbTransaction::Commit) == -1)
  {
    PRINT_ERROR(myTransaction3->getNdbError());
    
    if (myTransaction3->getNdbError().code != 839)
    {
      ndbout << "Expected error 839" << endl;
      g_ndb->closeTransaction(myTransaction3);
      return NDBT_FAILED;
    }
  }
  g_ndb->closeTransaction(myTransaction3);

  return NDBT_OK;
}

#define CHECK_VAL_EQ(ref, test) {                \
    if ((ref) != (test)) {                       \
      ndbout << "Equality failed at line " << __LINE__ << "\n" \
             << test << " != " << ref << "\n"; \
      return NDBT_FAILED;                      \
    } }

#define CHECK_BYTES_EQ(ref, test, len) {        \
    if (memcmp((ref), (test), (len))) {         \
      ndbout << "Bytes differ at line " << __LINE__ << "\n"; \
      return NDBT_FAILED;                                    \
    }} 




static int do_read()
{
  NdbRecAttr *myRecAttr[column_count_table1];
  NdbRecAttr *myRecAttr2[column_count_table2];
  NdbRecAttr *myRecAttr3[column_count_table3];

  const NdbDictionary::Table *myTable= g_dict->getTable(g_tablename1);
  const NdbDictionary::Table *myTable2 = g_dict->getTable(g_tablename2);
  const NdbDictionary::Table *myTable3 = g_dict->getTable(g_tablename3);

  if (myTable == NULL || myTable2 == NULL || myTable3 == NULL)
  {
    PRINT_ERROR(g_dict->getNdbError());
    return NDBT_FAILED;
  }

  NdbTransaction *myTransaction= g_ndb->startTransaction();
  if (myTransaction == NULL)
  {
    PRINT_ERROR(g_ndb->getNdbError());
    return NDBT_FAILED;
  }

  //Define Scan Operation for T_DEF1
  NdbScanOperation *myScanOp = myTransaction->getNdbScanOperation(myTable);
  if (myScanOp == NULL)
  {
    PRINT_ERROR(myTransaction->getNdbError());
    g_ndb->closeTransaction(myTransaction);
    return NDBT_FAILED;
  }

  if(myScanOp->readTuples(NdbOperation::LM_CommittedRead) == -1)
  {
    PRINT_ERROR(myTransaction->getNdbError());
    g_ndb->closeTransaction(myTransaction);
    return NDBT_FAILED;
  }

  myRecAttr[0] = myScanOp->getValue("PK");
  myRecAttr[1] = myScanOp->getValue("C1");
  myRecAttr[2] = myScanOp->getValue("C2");
  myRecAttr[3] = myScanOp->getValue("C3");
  myRecAttr[4] = myScanOp->getValue("C4");
  myRecAttr[5] = myScanOp->getValue("C5");
  myRecAttr[6] = myScanOp->getValue("C6");
  myRecAttr[7] = myScanOp->getValue("C7");

  for (unsigned int i = 0; i < column_count_table1; i++)
    if (myRecAttr[i] == NULL)
    {
      PRINT_ERROR(myTransaction->getNdbError());
      g_ndb->closeTransaction(myTransaction);
      return NDBT_FAILED;
    }

  //Define Scan Operation for T_DEF2
  NdbScanOperation *myScanOp2 = myTransaction->getNdbScanOperation(myTable2);
  if (myScanOp2 == NULL)
  {
    PRINT_ERROR(myTransaction->getNdbError());
    g_ndb->closeTransaction(myTransaction);
    return NDBT_FAILED;
  }

  if(myScanOp2->readTuples(NdbOperation::LM_CommittedRead) == -1)
  {
    PRINT_ERROR(myTransaction->getNdbError());
    g_ndb->closeTransaction(myTransaction);
    return NDBT_FAILED;
  }

  myRecAttr2[0] = myScanOp2->getValue("PK");
  myRecAttr2[1] = myScanOp2->getValue("C1");
  if (myRecAttr2[0] == NULL || myRecAttr2[1] == NULL)
  {
    PRINT_ERROR(myTransaction->getNdbError());
    g_ndb->closeTransaction(myTransaction);
    return NDBT_FAILED;
  }

  //Define Scan Operation for T_DEF3  
  NdbScanOperation *myScanOp3 = myTransaction->getNdbScanOperation(myTable3);
  if (myScanOp3 == NULL)
  {
    PRINT_ERROR(myTransaction->getNdbError());
    g_ndb->closeTransaction(myTransaction);
    return NDBT_FAILED;
  }

  if(myScanOp3->readTuples(NdbOperation::LM_CommittedRead) == -1)
  {
    PRINT_ERROR(myTransaction->getNdbError());
    g_ndb->closeTransaction(myTransaction);
    return NDBT_FAILED;
  }

  myRecAttr3[0] = myScanOp3->getValue("PK");
  myRecAttr3[1] = myScanOp3->getValue("C1");
  if (myRecAttr3[0] == NULL || myRecAttr3[1] == NULL)
  {
    PRINT_ERROR(myTransaction->getNdbError());
    g_ndb->closeTransaction(myTransaction);
    return NDBT_FAILED;
  }

  //Execute the Transcation for the 3 scan operations
  if(myTransaction->execute(NdbTransaction::NoCommit) != 0)
  {
    PRINT_ERROR(myTransaction->getNdbError());
    g_ndb->closeTransaction(myTransaction);
    return NDBT_FAILED;
  }

  //The following print out the result
  int check;
  ndbout<< "Table: " << g_tablename1 << endl;
//   ndbout << "PK";
//   for (unsigned int i = 0; i < column_count_table1; i++)
//     ndbout << "\tC" << i ;
//   ndbout << endl;
  while((check = myScanOp->nextResult(true)) == 0){
    do {
//       for (Uint32 i = 0; i < column_count_table1; i++)
//         ndbout << *myRecAttr[i] << "\t";
//       ndbout << endl;
      
      for (Uint32 i = 0; i < column_count_table1; i++)
      {
        /* Check that all columns are non NULL except c6 */
        CHECK_VAL_EQ((i == 6), myRecAttr[i]->isNULL());
      }

      CHECK_VAL_EQ(tab1_c1_default, (int) myRecAttr[1]->int32_value());
      CHECK_VAL_EQ(tab1_c2_default, myRecAttr[2]->float_value());
      CHECK_VAL_EQ(tab1_c3_default, myRecAttr[3]->double_value());
      CHECK_BYTES_EQ(tab1_c4_default, (const char*) myRecAttr[4]->aRef(), tab1_c4_default_siglen);
      CHECK_BYTES_EQ(tab1_c5_default, (const char*) myRecAttr[5]->aRef(), tab1_c5_default_siglen); 
      CHECK_BYTES_EQ(tab1_c6_default, (const char*) myRecAttr[6]->aRef(), tab1_c6_default_siglen);
      CHECK_BYTES_EQ(tab1_c7_default, (const char*) myRecAttr[7]->aRef(), tab1_c7_default_siglen);
    } while((check = myScanOp->nextResult(false)) == 0);

    if(check == -1)
    {
      ndbout << "Error with transaction " << check << " " 
             << myTransaction->getNdbError().code << "\n";
      return NDBT_FAILED;
    }
  }

  ndbout<< "Table: " << g_tablename2 << endl;
  // ndbout << "PK\tC1" << endl;
  while((check = myScanOp2->nextResult(true)) == 0){
    do {
//       for (Uint32 i = 0; i < column_count_table2; i++)
//       {
//         if (i == 1)
//           ndbout << myRecAttr2[i]->get_size_in_bytes() << "  ";
//         ndbout << *myRecAttr2[i] << "\t";
//       }
//       ndbout << endl;
      const char* valPtr= (const char*)myRecAttr2[1]->aRef();
      char default_data[tab2_c1_default_len + 2];
      default_data[0] = (tab2_c1_default_len >> 0) & 0xff;
      default_data[1] = (tab2_c1_default_len >> 8) & 0xff;
      memset(default_data + 2, tab2_c1_default_char, tab2_c1_default_len);

      CHECK_BYTES_EQ(default_data, valPtr, tab2_c1_default_len + 2);

    } while((check = myScanOp2->nextResult(false)) == 0);
  }


  return NDBT_OK;
}

int main(int argc, char* argv[])
{
  int ret;
  ndb_init();

  ndbout << "testNativeDefault started" << endl;

  if (!connect_ndb())
  {
    ndbout << "Failed to connect to NDB" << endl;
    return NDBT_ProgramExit(NDBT_FAILED);
  }
  ndbout << "connected.." << endl;

  ndbout << "checking create table errors..." << endl;
  if ((ret = create_table_error()) != NDBT_OK)
    return NDBT_ProgramExit(ret);

  ndbout << "creating table..." << endl;
  if ((ret = create_table()) != NDBT_OK)
    return NDBT_ProgramExit(ret);

  ndbout << "inserting..." << endl;
  if ((ret = do_insert()) != NDBT_OK)
    return NDBT_ProgramExit(ret);

  ndbout << "reading..." << endl;
  if ((ret = do_read()) != NDBT_OK)
    return NDBT_ProgramExit(ret);

  if ((ret = drop_table()) != NDBT_OK)
    return NDBT_ProgramExit(ret);

  ndbout << "done!" << endl;

  disconnect_ndb();

  ndbout << "All tests successful" << endl;
  return NDBT_ProgramExit(NDBT_OK);
}
