List:Commits« Previous MessageNext Message »
From:knielsen Date:November 9 2006 10:08am
Subject:bk commit into 5.1 tree (knielsen:1.2330)
View as plain text  
Below is the list of changes that have just been committed into a local
5.1 repository of knielsen. When knielsen does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2006-11-09 11:08:47+01:00, knielsen@ymer.(none) +8 -0
  WL#1190
  Implement dynattr bit types.

  sql/ha_ndbcluster.cc@stripped, 2006-11-09 11:08:43+01:00, knielsen@ymer.(none) +3 -0
    Implement dynattr bit types.

  storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp@stripped, 2006-11-09 11:08:43+01:00, knielsen@ymer.(none) +41 -0
    Implement dynattr bit types.

  storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp@stripped, 2006-11-09 11:08:43+01:00, knielsen@ymer.(none) +7 -5
    Implement dynattr bit types.

  storage/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp@stripped, 2006-11-09 11:08:43+01:00, knielsen@ymer.(none) +55 -24
    Implement dynattr bit types.

  storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp@stripped, 2006-11-09 11:08:43+01:00, knielsen@ymer.(none) +372 -6
    Implement dynattr bit types.

  storage/ndb/src/kernel/blocks/dbtup/test_dynbm.c@stripped, 2006-11-09 11:08:43+01:00, knielsen@ymer.(none) +228 -0
    New BitKeeper file ``storage/ndb/src/kernel/blocks/dbtup/test_dynbm.c''

  storage/ndb/src/kernel/blocks/dbtup/test_dynbm.c@stripped, 2006-11-09 11:08:43+01:00, knielsen@ymer.(none) +0 -0

  storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp@stripped, 2006-11-09 11:08:43+01:00, knielsen@ymer.(none) +2 -1
    Implement dynattr bit types.

  storage/ndb/test/src/NDBT_Tables.cpp@stripped, 2006-11-09 11:08:43+01:00, knielsen@ymer.(none) +11 -45
    Implement dynattr bit types.

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	knielsen
# Host:	ymer.(none)
# Root:	/usr/local/mysql/mysql-5.1-ndb-dynattr
--- New file ---
+++ storage/ndb/src/kernel/blocks/dbtup/test_dynbm.c	06/11/09 11:08:43
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <assert.h>

#define N (1024*1024)
#define S 65537
/* The number S must be relative prime to N. */

uint32_t bm[N*4];

uint32_t bms[N][4];
uint32_t len[N];
uint32_t pos[N];

typedef uint32_t Uint32;
#define MEMCOPY_NO_WORDS(to, from, no_of_words) \
  memcpy((to), (void*)(from), (size_t)(no_of_words << 2));

/****************************************************************************/
static void
getbits(const Uint32 *src, Uint32 bit_pos, Uint32 *dst, Uint32 count)
{
  Uint32 val;

  /* Move to start word in src. */
  src+= bit_pos>>5;
  bit_pos&= 31;

  /*
    If word-aligned, copy word-for-word is faster and avoids edge
    cases with undefined bitshift operations.
  */
  if (bit_pos==0)
  {
    MEMCOPY_NO_WORDS(dst, src, count>>5);
    src+= count>>5;
    dst+= count>>5;
    count&= 31;
  }
  else
  {
    while(count >= 32)
    {
      /*
        Get bits 0-X from first source word.
        Get bits (X+1)-31 from second source word.
        Handle endian so that we store bit 0 in the first byte, and bit 31 in
        the last byte, so that we don't waste space on 32-bit aligning the
        bitmap.
      */
#ifdef WORDS_BIGENDIAN
      Uint32 firstpart_len= 32-bit_pos;
      val= *src++ & (((Uint32)1<<firstpart_len)-1);
      val|= *src & ((Uint32)0xffffffff << firstpart_len);
#else
      val= *src++ >> bit_pos;
      val|= *src << (32-bit_pos);
#endif
      *dst++= val;
      count-= 32;
    }
  }

  /* Handle any partial word at the end. */
  if (count>0)
  {
    if (bit_pos+count <= 32)
    {
      /* Last part is wholly contained in one source word. */
#ifdef WORDS_BIGENDIAN
      val= *src >> (32-(bit_pos+count));
#else
      val= *src >> bit_pos;
#endif
    }
    else
    {
      /* Need to assemble last part from two source words. */
#ifdef WORDS_BIGENDIAN
      Uint32 firstpart_len= 32-bit_pos;
      val= *src++ & (((Uint32)1<<firstpart_len)-1);
      val|= (*src >> (32-count)) & ((Uint32)0xffffffff << firstpart_len);
#else
      val= *src++ >> bit_pos;
      val|= *src << (32-bit_pos);
#endif
    }
    /* Mask off any unused bits. */
    *dst= val & (((Uint32)1<<count)-1);
  }
}

static void
setbits(const Uint32 *src, Uint32 *dst, Uint32 bit_pos, Uint32 count)
{
  Uint32 val;

  /* Move to start word in dst. */

  dst+= bit_pos>>5;
  bit_pos&= 31;

#ifdef WORDS_BIGENDIAN
  Uint32 low_mask= ((Uint32)0xffffffff)<<(32-bit_pos);
  Uint32 high_mask= ~low_mask;
#else
  Uint32 low_mask= (((Uint32)1)<<bit_pos) - 1;
  Uint32 high_mask= ~low_mask;
#endif

  if (bit_pos==0)
  {
    MEMCOPY_NO_WORDS(dst, src, count>>5);
    src+= count>>5;
    dst+= count>>5;
    count&= 31;
  }
  else
  {
    while (count >= 32)
    {
      val= *src++;
#ifdef WORDS_BIGENDIAN
      *dst= (*dst&low_mask) | (val&high_mask);
      dst++;
      *dst= (*dst&high_mask) | (val&low_mask);
#else
      *dst= (*dst&low_mask) | (val<<bit_pos);
      dst++;
      *dst= (*dst&high_mask) | (val>>(32-bit_pos));
#endif
      count-= 32;
    }
  }

  /* Handle any partial word at the end. */
  if (count > 0)
  {
    val= *src;
    if (bit_pos+count <= 32)
    {
      /* Remaining part fits in one word of destination. */
      Uint32 end_mask= (((Uint32)1)<<count) - 1;
#ifdef WORDS_BIGENDIAN
      Uint32 shift= (32-(bit_pos+count));
      *dst= (*dst&~(end_mask<<shift)) | ((val&end_mask)<<shift);
#else
      *dst= (*dst&~(end_mask<<bit_pos)) | ((val&end_mask)<<bit_pos);
#endif
    }
    else
    {
      /* Need to split the remaining part across two destination words. */
#ifdef WORDS_BIGENDIAN
      *dst= (*dst&low_mask) | (val&high_mask);
      dst++;
      Uint32 shift= 32-count;
      Uint32 end_mask= ((((Uint32)1)<<(bit_pos+count-32)) - 1) << (32-bit_pos);
      *dst= (*dst&~(end_mask<<shift)) | ((val&end_mask)<<shift);
#else
      *dst= (*dst&low_mask) | (val<<bit_pos);
      dst++;
      Uint32 end_mask= (((Uint32)1)<<(count+bit_pos-32)) - 1;
      *dst= (*dst&~end_mask) | ((val>>(32-bit_pos))&end_mask);
#endif
    }
  }
}
/****************************************************************************/

/* Set up a bunch of test bit fields. */
void fill(void)
{
  uint32_t i,j;
  uint32_t p= 0;

  for(i= 0; i<N; i++)
  {
    memset(bms[i], 0, sizeof(bms[i]));
    pos[i]= p;
    do
      len[i]= rand()%128;
    while (!len[i]);
    p+= len[i];
    for(j= 0; j<len[i]; j++)
      if(rand()%2)
        bms[i][j>>5]|= (((uint32_t)1)<<(j&31));
  }
}

void write(void)
{
  uint32_t i, idx;

  for(i=0, idx=0; i<N; i++, idx+= S)
  {
    if(idx>=N)
      idx-= N;
    setbits(&(bms[idx][0]), &(bm[0]), pos[idx], len[idx]);
  }
}

void read(void)
{
  uint32_t buf[4];
  uint32_t i;

  for(i=0; i<N; i++)
  {
    getbits(&(bm[0]), pos[i], &(buf[0]), len[i]);
    assert(0==memcmp(buf, bms[i], ((len[i]+31)>>5)<<2));
  }
}

int main(int argc, char *argv[])
{
  uint32_t i;

  srand(1);
  fill();
  write();
  read();

  exit(0);
  return 0;
}


--- 1.54/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp	2006-11-09 11:08:55 +01:00
+++ 1.55/storage/ndb/src/kernel/blocks/dbtup/Dbtup.hpp	2006-11-09 11:08:55 +01:00
@@ -357,6 +357,7 @@ typedef Ptr<Fragoperrec> FragoperrecPtr;
     Uint32 noOfDynNullBits;
     Uint32 noOfDynVar;
     Uint32 noOfDynFix;
+    Uint32 noOfDynamic;
     Uint32 tabDesOffset[7];
     Uint32 desAllocSize;
     Uint32 tableDescriptor;
@@ -1019,6 +1020,10 @@ ArrayPool<TupTriggerData> c_triggerPool;
       Uint16 m_no_of_dynamic;                   // Total no. of dynamic attrs
       Uint16 m_no_of_dyn_fix;                   // No. of fixsize dynamic
       Uint16 m_no_of_dyn_var;                   // No. of varsize dynamic
+      /*
+        Note that due to bit types, we may have
+            m_no_of_dynamic > m_no_of_dyn_fix + m_no_of_dyn_var
+      */
     } m_attributes[2];
     
     // Lists of trigger data for active triggers
@@ -2047,6 +2052,42 @@ private:
   bool updateDynFixedSizeNULLable(Uint32* inBuffer,
                                   KeyReqStruct *req_struct,
                                   Uint32  attrDes2);
+
+//------------------------------------------------------------------
+//------------------------------------------------------------------
+  bool readDynBitsNotNULL(Uint32* outBuffer,
+                          KeyReqStruct *req_struct,
+                          AttributeHeader* ahOut,
+                          Uint32  attrDes2);
+  bool readDynBitsNULLable(Uint32* outBuffer,
+                           KeyReqStruct *req_struct,
+                           AttributeHeader* ahOut,
+                           Uint32  attrDes2);
+  bool readDynBitsExpandedNotNULL(Uint32* outBuffer,
+                                  KeyReqStruct *req_struct,
+                                  AttributeHeader* ahOut,
+                                  Uint32  attrDes2);
+  bool readDynBitsShrunkenNotNULL(Uint32* outBuffer,
+                                  KeyReqStruct *req_struct,
+                                  AttributeHeader* ahOut,
+                                  Uint32  attrDes2);
+  bool readDynBitsExpandedNULLable(Uint32* outBuffer,
+                                   KeyReqStruct *req_struct,
+                                   AttributeHeader* ahOut,
+                                   Uint32  attrDes2);
+  bool readDynBitsShrunkenNULLable(Uint32* outBuffer,
+                                   KeyReqStruct *req_struct,
+                                   AttributeHeader* ahOut,
+                                   Uint32  attrDes2);
+
+//------------------------------------------------------------------
+//------------------------------------------------------------------
+  bool updateDynBitsNotNULL(Uint32* inBuffer,
+                            KeyReqStruct *req_struct,
+                            Uint32  attrDes2);
+  bool updateDynBitsNULLable(Uint32* inBuffer,
+                             KeyReqStruct *req_struct,
+                             Uint32  attrDes2);
 
 //------------------------------------------------------------------
 //------------------------------------------------------------------

--- 1.47/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp	2006-11-09 11:08:55 +01:00
+++ 1.48/storage/ndb/src/kernel/blocks/dbtup/DbtupExecQuery.cpp	2006-11-09 11:08:55 +01:00
@@ -222,7 +222,7 @@ Dbtup::calculateChecksum(Tuple_header* t
   // includes tupVersion
   //printf("%p - ", tuple_ptr);
   
-  if (regTabPtr->m_attributes[MM].m_no_of_varsize ||
+  if (regTabPtr->m_attributes[MM].m_no_of_varsize +
       regTabPtr->m_attributes[MM].m_no_of_dynamic)
     rec_size += Tuple_header::HeaderSize;
   
@@ -1145,10 +1145,10 @@ Dbtup::prepare_initial_insert(KeyReqStru
 
     /* Set up the offsets for the attribute data. */
     dst->m_dyn_offset_arr_ptr= len_ptr;
-    dst->m_dyn_len_offset= mm_dyns;
+    dst->m_dyn_len_offset= mm_dynvar+mm_dynfix;
     dst->m_max_dyn_offset= regTabPtr->m_offsets[MM].m_max_dyn_offset;
     pos_ptr= len_ptr;
-    len_ptr= pos_ptr+mm_dyns;
+    len_ptr= pos_ptr+mm_dynvar+mm_dynfix;
     /* Reserve room for bitmap + shrunken offset array + padding. */
     pos= bm_size_in_bytes + 4*((mm_dynvar+2)>>1);
     for(Uint32 i= 0; i<mm_dynvar; i++)
@@ -2636,6 +2636,8 @@ Dbtup::expand_tuple(KeyReqStruct* req_st
   
   Uint16 dd_tot= tabPtrP->m_no_of_disk_attributes;
   Uint16 mm_vars= tabPtrP->m_attributes[MM].m_no_of_varsize;
+  Uint16 mm_dynvar= tabPtrP->m_attributes[MM].m_no_of_dyn_var;
+  Uint16 mm_dynfix= tabPtrP->m_attributes[MM].m_no_of_dyn_fix;
   Uint16 mm_dyns= tabPtrP->m_attributes[MM].m_no_of_dynamic;
   Uint32 fix_size= tabPtrP->m_offsets[MM].m_varpart_offset;
   Uint32 order_desc= tabPtrP->m_real_order_descriptor;
@@ -2701,7 +2703,7 @@ Dbtup::expand_tuple(KeyReqStruct* req_st
     src_ptr = ALIGN_WORD(((char*)src_ptr)+step);
 
     dst->m_dyn_offset_arr_ptr= req_struct->var_pos_array+2*mm_vars;
-    dst->m_dyn_len_offset= mm_dyns;
+    dst->m_dyn_len_offset= mm_dynvar+mm_dynfix;
     dst->m_max_dyn_offset= tabPtrP->m_offsets[MM].m_max_dyn_offset;
     dst->m_dyn_data_ptr= (char*)dst_ptr;
     dst_ptr= expand_dyn_part(dst, tabPtrP, dyn_src_data,
@@ -2726,7 +2728,7 @@ Dbtup::expand_tuple(KeyReqStruct* req_st
   if(disk && dd_tot)
   {
     const Uint16 dd_vars= tabPtrP->m_attributes[DD].m_no_of_varsize;
-    order+= mm_vars+mm_dyns;
+    order+= mm_vars+mm_dynvar+mm_dynfix;
     
     if(bits & Tuple_header::DISK_INLINE)
     {

--- 1.33/storage/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp	2006-11-09 11:08:55 +01:00
+++ 1.34/storage/ndb/src/kernel/blocks/dbtup/DbtupMeta.cpp	2006-11-09 11:08:55 +01:00
@@ -392,31 +392,46 @@ void Dbtup::execTUP_ADD_ATTRREQ(Signal* 
     /*
        The dynamic attribute format always require a 'null' bit. So
        storing NOT NULL attributes as dynamic is not all that useful
-       (but not harmful in any way either.
+       (but not harmful in any way either).
        Later we might implement NOT NULL DEFAULT xxx by storing the value
        xxx internally as 'null'.
     */
 
     Uint32 null_pos= regTabPtr.p->m_dyn_null_bits;
-    AttributeOffset::setNullFlagPos(attrDes2, null_pos);
 
     if (AttributeDescriptor::getArrayType(attrDescriptor)==NDB_ARRAYTYPE_FIXED)
     {
       /* A fixed-size dynamic attribute. */
       ljam();
-      regTabPtr.p->m_attributes[ind].m_no_of_dyn_fix++;
-      /* ToDo: Handle bit type. */
-      ndbrequire(bytes > 0);
-      /*
-        We use one NULL bit per 4 bytes of dynamic fixed-size attribute. So
-        do not store longer than 64 bytes (16 bit), since it is more efficient
-        to store those as dynamic varsize internally.
-        ToDo: Should this conversion >64bit dynfix ->dynvar instead happen
-        transparently here in Dbtup?
-      */
-      ndbrequire(bytes <= 64);
-      Uint32 null_bits= (bytes+3) >> 2;
-      regTabPtr.p->m_dyn_null_bits+= null_bits;
+      if (AttributeDescriptor::getSize(attrDescriptor)==0)
+      {
+        /*
+          Bit type. These are stored directly in the bitmap.
+          This means that we will still use some space for a dynamic NULL
+          bittype if a following dynamic attribute is non-NULL.
+        */
+        Uint32 bits= AttributeDescriptor::getArraySize(attrDescriptor);
+        /*
+          The NULL bit is stored after the data bits, so that we automatically
+          ensure that the full size bitmap is stored when non-NULL.
+        */
+        null_pos+= bits;
+        regTabPtr.p->m_dyn_null_bits+= bits+1;
+      }
+      else
+      {
+        regTabPtr.p->m_attributes[ind].m_no_of_dyn_fix++;
+        /*
+          We use one NULL bit per 4 bytes of dynamic fixed-size attribute. So
+          do not store longer than 64 bytes (16 bit), since it is more efficient
+          to store those as dynamic varsize internally.
+          ToDo: Should this conversion >64bit dynfix ->dynvar instead happen
+          transparently here in Dbtup?
+        */
+        ndbrequire(bytes <= 64);
+        Uint32 null_bits= (bytes+3) >> 2;
+        regTabPtr.p->m_dyn_null_bits+= null_bits;
+      }
     }
     else
     {
@@ -425,8 +440,10 @@ void Dbtup::execTUP_ADD_ATTRREQ(Signal* 
       regTabPtr.p->m_attributes[ind].m_no_of_dyn_var++;
       regTabPtr.p->m_dyn_null_bits++;
     }
+    AttributeOffset::setNullFlagPos(attrDes2, null_pos);
+
     ndbassert((regTabPtr.p->m_attributes[ind].m_no_of_dyn_var +
-               regTabPtr.p->m_attributes[ind].m_no_of_dyn_fix) ==
+               regTabPtr.p->m_attributes[ind].m_no_of_dyn_fix) <=
               regTabPtr.p->m_attributes[ind].m_no_of_dynamic);
   }
   handleCharsetPos(csNumber, regTabPtr.p->charsetArray,
@@ -701,6 +718,7 @@ Dbtup::handleAlterTabPrepare(Signal *sig
   Uint32 dyn_nullbits= regTabPtr->m_dyn_null_bits;
   Uint32 noDynFix= regTabPtr->m_attributes[MM].m_no_of_dyn_fix;
   Uint32 noDynVar= regTabPtr->m_attributes[MM].m_no_of_dyn_var;
+  Uint32 noDynamic= regTabPtr->m_attributes[MM].m_no_of_dynamic;
   for (Uint32 i= 0; i<noOfNewAttr; i++)
   {
     Uint32 attrDescriptor= *attrInfo++;
@@ -714,17 +732,25 @@ Dbtup::handleAlterTabPrepare(Signal *sig
     handleCharsetPos(csNumber, CharsetArray, newNoOfCharsets,
                      charsetIndex, attrDes2);
 
-    AttributeOffset::setNullFlagPos(attrDes2, dyn_nullbits);
+    Uint32 null_pos= dyn_nullbits;
     Uint32 arrType= AttributeDescriptor::getArrayType(attrDescriptor);
+    noDynamic++;
     if (arrType==NDB_ARRAYTYPE_FIXED)
     {
       Uint32 words= AttributeDescriptor::getSizeInWords(attrDescriptor);
-      noDynFix++;
 
       if(AttributeDescriptor::getSize(attrDescriptor) > 0)
+      {
+        noDynFix++;
         dyn_nullbits+= words;
+      }
       else
-        ndbrequire(false);                    // ToDo: Handle bit types
+      {
+        /* Bit type. */
+        Uint32 bits= AttributeDescriptor::getArraySize(attrDescriptor);
+        null_pos+= bits;
+        dyn_nullbits+= bits+1;
+      }
 
       ndbrequire(words <= 16);                // ToDo: Handle fix>64 bytes
     }
@@ -733,6 +759,7 @@ Dbtup::handleAlterTabPrepare(Signal *sig
       noDynVar++;
       dyn_nullbits++;
     }
+    AttributeOffset::setNullFlagPos(attrDes2, null_pos);
 
     *attrDesPtr++= attrDescriptor;
     *attrDesPtr++= attrDes2;
@@ -740,10 +767,11 @@ Dbtup::handleAlterTabPrepare(Signal *sig
   ndbassert(newNoOfCharsets==charsetIndex);
 
   regAlterTabOpPtr.p->noOfDynNullBits= dyn_nullbits;
-  ndbassert(noDynFix + noDynVar ==
+  ndbassert(noDynamic ==
             regTabPtr->m_attributes[MM].m_no_of_dynamic + noOfNewAttr);
   regAlterTabOpPtr.p->noOfDynFix= noDynFix;
   regAlterTabOpPtr.p->noOfDynVar= noDynVar;
+  regAlterTabOpPtr.p->noOfDynamic= noDynamic;
 
   /* Allocate the new (possibly larger) dynamic descriptor. */
   allocSize= getDynTabDescrOffsets((dyn_nullbits+31)>>5,
@@ -825,8 +853,7 @@ Dbtup::handleAlterTableCommit(Signal *si
   regTabPtr->m_no_of_attributes= regAlterTabOpPtr.p->newNoOfAttrs;
   regTabPtr->m_attributes[MM].m_no_of_dyn_fix= regAlterTabOpPtr.p->noOfDynFix;
   regTabPtr->m_attributes[MM].m_no_of_dyn_var= regAlterTabOpPtr.p->noOfDynVar;
-  regTabPtr->m_attributes[MM].m_no_of_dynamic=
-    regAlterTabOpPtr.p->noOfDynFix + regAlterTabOpPtr.p->noOfDynVar;
+  regTabPtr->m_attributes[MM].m_no_of_dynamic= regAlterTabOpPtr.p->noOfDynamic;
   regTabPtr->m_dyn_null_bits= regAlterTabOpPtr.p->noOfDynNullBits;
 
   /* Install the new (larger) table descriptors. */
@@ -946,6 +973,7 @@ Dbtup::computeTableMetaData(Tablerec *re
   Uint32 statvar_count= 0;
   Uint32 dynfix_count= 0;
   Uint32 dynvar_count= 0;
+  Uint32 dynamic_count= 0;
   regTabPtr->blobAttributeMask.clear();
   regTabPtr->notNullAttributeMask.clear();
   bzero(regTabPtr->dynVarSizeMask, dyn_null_words<<2);
@@ -993,6 +1021,7 @@ Dbtup::computeTableMetaData(Tablerec *re
     else
     {
       /* Dynamic attribute. */
+      dynamic_count++;
       ndbassert(ind==MM);
       ndbrequire(extType != NDB_TYPE_BLOB && extType != NDB_TYPE_TEXT);
       Uint32 null_pos= AttributeOffset::getNullFlagPos(attrDes2);
@@ -1019,6 +1048,7 @@ Dbtup::computeTableMetaData(Tablerec *re
   }
   ndbassert(dynvar_count==regTabPtr->m_attributes[MM].m_no_of_dyn_var);
   ndbassert(dynfix_count==regTabPtr->m_attributes[MM].m_no_of_dyn_fix);
+  ndbassert(dynamic_count==regTabPtr->m_attributes[MM].m_no_of_dynamic);
   ndbassert(statvar_count==regTabPtr->m_attributes[MM].m_no_of_varsize);
 
   regTabPtr->m_offsets[MM].m_fix_header_size= 
@@ -1035,7 +1065,8 @@ Dbtup::computeTableMetaData(Tablerec *re
     regTabPtr->m_offsets[DD].m_fix_header_size += Tuple_header::HeaderSize;
 
   Uint32 mm_vars= regTabPtr->m_attributes[MM].m_no_of_varsize;
-  Uint32 mm_dyns= regTabPtr->m_attributes[MM].m_no_of_dynamic;
+  Uint32 mm_dyns= regTabPtr->m_attributes[MM].m_no_of_dyn_fix +
+                  regTabPtr->m_attributes[MM].m_no_of_dyn_var;
   Uint32 dd_vars= regTabPtr->m_attributes[MM].m_no_of_varsize;
   Uint32 dd_dyns= regTabPtr->m_attributes[DD].m_no_of_dynamic;
 
@@ -1063,7 +1094,7 @@ Dbtup::computeTableMetaData(Tablerec *re
     offset in each offset array (for easy computation of final length).
     Also one word for storing total length of varsize+dynamic part
   */
-  if(mm_vars + mm_dyns)
+  if(mm_vars + regTabPtr->m_attributes[MM].m_no_of_dynamic)
   {
     total_rec_size+= (mm_vars + 2) >> 1;
     total_rec_size+= regTabPtr->m_offsets[MM].m_dyn_null_words;

--- 1.29/storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp	2006-11-09 11:08:55 +01:00
+++ 1.30/storage/ndb/src/kernel/blocks/dbtup/DbtupRoutines.cpp	2006-11-09 11:08:55 +01:00
@@ -146,18 +146,30 @@ Dbtup::setUpQueryRoutines(Tablerec *regT
     } else {
       if (AttributeDescriptor::getNullable(attrDescr)) {
         if (AttributeDescriptor::getArrayType(attrDescr) == NDB_ARRAYTYPE_FIXED){
-          ljam();
-          regTabPtr->readFunctionArray[i]= &Dbtup::readDynFixedSizeNULLable;
-          regTabPtr->updateFunctionArray[i]= &Dbtup::updateDynFixedSizeNULLable;
+          if (AttributeDescriptor::getSize(attrDescr) == 0){
+            ljam(); 
+            regTabPtr->readFunctionArray[i]= &Dbtup::readDynBitsNULLable;
+            regTabPtr->updateFunctionArray[i]= &Dbtup::updateDynBitsNULLable;
+          } else {
+            ljam();
+            regTabPtr->readFunctionArray[i]= &Dbtup::readDynFixedSizeNULLable;
+            regTabPtr->updateFunctionArray[i]= &Dbtup::updateDynFixedSizeNULLable;
+          }
         } else {
           regTabPtr->readFunctionArray[i]= &Dbtup::readDynVarSizeNULLable;
           regTabPtr->updateFunctionArray[i]= &Dbtup::updateDynVarSizeNULLable;
         }
       } else {
         if (AttributeDescriptor::getArrayType(attrDescr) == NDB_ARRAYTYPE_FIXED){
-          ljam();
-          regTabPtr->readFunctionArray[i]= &Dbtup::readDynFixedSizeNotNULL;
-          regTabPtr->updateFunctionArray[i]= &Dbtup::updateDynFixedSizeNotNULL;
+          if (AttributeDescriptor::getSize(attrDescr) == 0){
+            ljam(); 
+            regTabPtr->readFunctionArray[i]= &Dbtup::readDynBitsNotNULL;
+            regTabPtr->updateFunctionArray[i]= &Dbtup::updateDynBitsNotNULL;
+          } else {
+            ljam();
+            regTabPtr->readFunctionArray[i]= &Dbtup::readDynFixedSizeNotNULL;
+            regTabPtr->updateFunctionArray[i]= &Dbtup::updateDynFixedSizeNotNULL;
+          }
         } else {
           regTabPtr->readFunctionArray[i]= &Dbtup::readDynVarSizeNotNULL;
           regTabPtr->updateFunctionArray[i]= &Dbtup::updateDynVarSizeNotNULL;
@@ -737,6 +749,296 @@ Dbtup::readDynFixedSizeShrunkenNULLable(
                                          ahOut, attrDes2);
 }
 
+/*
+  The getbits() and setbits() functions handle the shuffling of bit
+  types in and out of the dynamic bitmaps. They are a bit special in
+  that they need to keep the first byte untouched (for the bitmap
+  length) as well as the last two bytes (to avoid padding), so they
+  need to shift from different directions depending on the host
+  endianness.
+ */
+static void
+getbits(const Uint32 *src, Uint32 bit_pos, Uint32 *dst, Uint32 count)
+{
+  Uint32 val;
+
+  /* Move to start word in src. */
+  src+= bit_pos>>5;
+  bit_pos&= 31;
+
+  /*
+    If word-aligned, copy word-for-word is faster and avoids edge
+    cases with undefined bitshift operations.
+  */
+  if (bit_pos==0)
+  {
+    MEMCOPY_NO_WORDS(dst, src, count>>5);
+    src+= count>>5;
+    dst+= count>>5;
+    count&= 31;
+  }
+  else
+  {
+    while(count >= 32)
+    {
+      /*
+        Get bits 0-X from first source word.
+        Get bits (X+1)-31 from second source word.
+        Handle endian so that we store bit 0 in the first byte, and bit 31 in
+        the last byte, so that we don't waste space on 32-bit aligning the
+        bitmap.
+      */
+#ifdef WORDS_BIGENDIAN
+      Uint32 firstpart_len= 32-bit_pos;
+      val= *src++ & (((Uint32)1<<firstpart_len)-1);
+      val|= *src & ((Uint32)0xffffffff << firstpart_len);
+#else
+      val= *src++ >> bit_pos;
+      val|= *src << (32-bit_pos);
+#endif
+      *dst++= val;
+      count-= 32;
+    }
+  }
+
+  /* Handle any partial word at the end. */
+  if (count>0)
+  {
+    if (bit_pos+count <= 32)
+    {
+      /* Last part is wholly contained in one source word. */
+#ifdef WORDS_BIGENDIAN
+      val= *src >> (32-(bit_pos+count));
+#else
+      val= *src >> bit_pos;
+#endif
+    }
+    else
+    {
+      /* Need to assemble last part from two source words. */
+#ifdef WORDS_BIGENDIAN
+      Uint32 firstpart_len= 32-bit_pos;
+      val= *src++ & (((Uint32)1<<firstpart_len)-1);
+      val|= (*src >> (32-count)) & ((Uint32)0xffffffff << firstpart_len);
+#else
+      val= *src++ >> bit_pos;
+      val|= *src << (32-bit_pos);
+#endif
+    }
+    /* Mask off any unused bits. */
+    *dst= val & (((Uint32)1<<count)-1);
+  }
+}
+
+static void
+setbits(const Uint32 *src, Uint32 *dst, Uint32 bit_pos, Uint32 count)
+{
+  Uint32 val;
+
+  /* Move to start word in dst. */
+
+  dst+= bit_pos>>5;
+  bit_pos&= 31;
+
+#ifdef WORDS_BIGENDIAN
+  Uint32 low_mask= ((Uint32)0xffffffff)<<(32-bit_pos);
+  Uint32 high_mask= ~low_mask;
+#else
+  Uint32 low_mask= (((Uint32)1)<<bit_pos) - 1;
+  Uint32 high_mask= ~low_mask;
+#endif
+
+  if (bit_pos==0)
+  {
+    MEMCOPY_NO_WORDS(dst, src, count>>5);
+    src+= count>>5;
+    dst+= count>>5;
+    count&= 31;
+  }
+  else
+  {
+    while (count >= 32)
+    {
+      val= *src++;
+#ifdef WORDS_BIGENDIAN
+      *dst= (*dst&low_mask) | (val&high_mask);
+      dst++;
+      *dst= (*dst&high_mask) | (val&low_mask);
+#else
+      *dst= (*dst&low_mask) | (val<<bit_pos);
+      dst++;
+      *dst= (*dst&high_mask) | (val>>(32-bit_pos));
+#endif
+      count-= 32;
+    }
+  }
+
+  /* Handle any partial word at the end. */
+  if (count > 0)
+  {
+    val= *src;
+    if (bit_pos+count <= 32)
+    {
+      /* Remaining part fits in one word of destination. */
+      Uint32 end_mask= (((Uint32)1)<<count) - 1;
+#ifdef WORDS_BIGENDIAN
+      Uint32 shift= (32-(bit_pos+count));
+      *dst= (*dst&~(end_mask<<shift)) | ((val&end_mask)<<shift);
+#else
+      *dst= (*dst&~(end_mask<<bit_pos)) | ((val&end_mask)<<bit_pos);
+#endif
+    }
+    else
+    {
+      /* Need to split the remaining part across two destination words. */
+#ifdef WORDS_BIGENDIAN
+      *dst= (*dst&low_mask) | (val&high_mask);
+      dst++;
+      Uint32 shift= 32-count;
+      Uint32 end_mask= ((((Uint32)1)<<(bit_pos+count-32)) - 1) << (32-bit_pos);
+      *dst= (*dst&~(end_mask<<shift)) | ((val&end_mask)<<shift);
+#else
+      *dst= (*dst&low_mask) | (val<<bit_pos);
+      dst++;
+      Uint32 end_mask= (((Uint32)1)<<(count+bit_pos-32)) - 1;
+      *dst= (*dst&~end_mask) | ((val>>(32-bit_pos))&end_mask);
+#endif
+    }
+  }
+}
+
+bool
+Dbtup::readDynBitsNotNULL(Uint32* outBuffer,
+                          KeyReqStruct *req_struct,
+                          AttributeHeader* ahOut,
+                          Uint32  attrDes2)
+{
+  ljam();
+  if(req_struct->is_expanded)
+    return readDynBitsExpandedNotNULL(outBuffer, req_struct, ahOut, attrDes2);
+  else
+    return readDynBitsShrunkenNotNULL(outBuffer, req_struct, ahOut, attrDes2);
+}
+
+bool
+Dbtup::readDynBitsNULLable(Uint32* outBuffer,
+                           KeyReqStruct *req_struct,
+                           AttributeHeader* ahOut,
+                           Uint32  attrDes2)
+{
+  ljam();
+  if(req_struct->is_expanded)
+    return readDynBitsExpandedNULLable(outBuffer, req_struct, ahOut, attrDes2);
+  else
+    return readDynBitsShrunkenNULLable(outBuffer, req_struct, ahOut, attrDes2);
+}
+
+bool
+Dbtup::readDynBitsShrunkenNotNULL(Uint32* outBuffer,
+                                  KeyReqStruct* req_struct,
+                                  AttributeHeader* ahOut,
+                                  Uint32 attrDes2)
+{
+  Uint32 *bm_ptr= (Uint32 *)(req_struct->m_var_data[MM].m_dyn_data_ptr);
+  Uint32 dyn_len= req_struct->m_var_data[MM].m_dyn_part_len;
+  ndbrequire(dyn_len != 0);
+  Uint32 bm_len= *((unsigned char *)bm_ptr); // In 16-bit words
+  Uint32 bitCount =
+    AttributeDescriptor::getArraySize(req_struct->attr_descriptor);
+  Uint32 pos = AttributeOffset::getNullFlagPos(attrDes2);
+  /* Make sure we have sufficient data in the row. */
+  ndbrequire((pos>>4)<bm_len);
+  /* The bit data is stored just before the NULL bit. */
+  ndbassert(pos>bitCount);
+  pos-= bitCount;
+
+  Uint32 indexBuf = req_struct->out_buf_index;
+  Uint32 newIndexBuf = indexBuf + ((bitCount + 31) >> 5);
+  Uint32 maxRead = req_struct->max_read;
+  if (newIndexBuf <= maxRead) {
+    ljam();
+    ahOut->setDataSize((bitCount + 31) >> 5);
+    req_struct->out_buf_index = newIndexBuf;
+
+    getbits(bm_ptr, pos, outBuffer+indexBuf, bitCount);
+    return true;
+  } else {
+    ljam();
+    terrorCode = ZTRY_TO_READ_TOO_MUCH_ERROR;
+    return false;
+  }//if
+}
+
+bool
+Dbtup::readDynBitsShrunkenNULLable(Uint32* outBuffer,
+                                   KeyReqStruct* req_struct,
+                                   AttributeHeader* ahOut,
+                                   Uint32 attrDes2)
+{
+  Uint32 *bm_ptr= (Uint32 *)(req_struct->m_var_data[MM].m_dyn_data_ptr);
+  Uint32 dyn_len= req_struct->m_var_data[MM].m_dyn_part_len;
+  /* Check for NULL (including the case of an empty bitmap). */
+  if(dyn_len == 0 ||
+     !dynNotNullFlagCheckLen(bm_ptr,
+                             *((unsigned char *)bm_ptr)<<1,
+                             attrDes2))
+  {
+    ljam();
+    ahOut->setNULL();
+    return true;
+  }
+
+  return readDynBitsShrunkenNotNULL(outBuffer, req_struct, ahOut, attrDes2);
+}
+
+bool
+Dbtup::readDynBitsExpandedNotNULL(Uint32* outBuffer,
+                                  KeyReqStruct* req_struct,
+                                  AttributeHeader* ahOut,
+                                  Uint32 attrDes2)
+{
+  Uint32 *bm_ptr= (Uint32 *)(req_struct->m_var_data[MM].m_dyn_data_ptr);
+  Uint32 bitCount =
+    AttributeDescriptor::getArraySize(req_struct->attr_descriptor);
+  Uint32 pos = AttributeOffset::getNullFlagPos(attrDes2);
+  /* The bit data is stored just before the NULL bit. */
+  ndbassert(pos>bitCount);
+  pos-= bitCount;
+
+  Uint32 indexBuf = req_struct->out_buf_index;
+  Uint32 newIndexBuf = indexBuf + ((bitCount + 31) >> 5);
+  Uint32 maxRead = req_struct->max_read;
+  if (newIndexBuf <= maxRead) {
+    ljam();
+    ahOut->setDataSize((bitCount + 31) >> 5);
+    req_struct->out_buf_index = newIndexBuf;
+
+    getbits(bm_ptr, pos, outBuffer+indexBuf, bitCount);
+    return true;
+  } else {
+    ljam();
+    terrorCode = ZTRY_TO_READ_TOO_MUCH_ERROR;
+    return false;
+  }//if
+}
+
+bool
+Dbtup::readDynBitsExpandedNULLable(Uint32* outBuffer,
+                                   KeyReqStruct* req_struct,
+                                   AttributeHeader* ahOut,
+                                   Uint32 attrDes2)
+{
+  Uint32 *bm_ptr= (Uint32 *)(req_struct->m_var_data[MM].m_dyn_data_ptr);
+  if(!dynNotNullFlagCheck(bm_ptr, attrDes2))
+  {
+    ljam();
+    ahOut->setNULL();
+    return true;
+  }
+
+  return readDynBitsExpandedNotNULL(outBuffer, req_struct, ahOut, attrDes2);
+}
+
 bool
 Dbtup::readDynVarSizeNotNULL(Uint32* outBuffer,
                              KeyReqStruct *req_struct,
@@ -1525,6 +1827,70 @@ Dbtup::updateDynFixedSizeNULLable(Uint32
     /* Clear the bits in the NULL bitmap. */
     bm_ptr[bm_idx]&= bm_mask1;
     bm_ptr[bm_idx+1]&= bm_mask2;
+    req_struct->in_buf_index= newIndex;
+    return true;
+  } else {
+    ljam();
+    terrorCode= ZAI_INCONSISTENCY_ERROR;
+    return false;
+  }
+}
+
+bool
+Dbtup::updateDynBitsNotNULL(Uint32* inBuffer,
+                            KeyReqStruct *req_struct,
+                            Uint32  attrDes2)
+{
+  Uint32 attrDescriptor= req_struct->attr_descriptor;
+  Uint32 pos= AttributeOffset::getNullFlagPos(attrDes2);
+  Uint32 bitCount = AttributeDescriptor::getArraySize(attrDescriptor);
+  Uint32 *bm_ptr= (Uint32 *)(req_struct->m_var_data[MM].m_dyn_data_ptr);
+  ljam();
+  dynSetBit(bm_ptr, pos);
+
+  Uint32 indexBuf= req_struct->in_buf_index;
+  Uint32 inBufLen= req_struct->in_buf_len;
+  AttributeHeader ahIn(inBuffer[indexBuf]);
+  Uint32 nullIndicator = ahIn.isNULL();
+  Uint32 newIndex = indexBuf + 1 + ((bitCount + 31) >> 5);
+
+  if (newIndex <= inBufLen) {
+    if (!nullIndicator) {
+      ndbassert(pos>=bitCount);
+      setbits(inBuffer+indexBuf+1, bm_ptr, pos-bitCount, bitCount);
+      req_struct->in_buf_index= newIndex;
+      return true;
+    } else {
+      ljam();
+      terrorCode= ZNOT_NULL_ATTR;
+      return false;
+    }//if
+  } else {
+    ljam();
+    terrorCode= ZAI_INCONSISTENCY_ERROR;
+    return false;
+  }//if
+  return true;
+}
+
+bool
+Dbtup::updateDynBitsNULLable(Uint32* inBuffer,
+                             KeyReqStruct *req_struct,
+                             Uint32  attrDes2)
+{
+  AttributeHeader ahIn(inBuffer[req_struct->in_buf_index]);
+  Uint32 nullIndicator= ahIn.isNULL();
+
+  if(!nullIndicator)
+    return updateDynBitsNotNULL(inBuffer, req_struct, attrDes2);
+
+  Uint32 pos= AttributeOffset::getNullFlagPos(attrDes2);
+  char *bm_ptr= req_struct->m_var_data[MM].m_dyn_data_ptr;
+
+  Uint32 newIndex= req_struct->in_buf_index + 1;
+  if (newIndex <= req_struct->in_buf_len) {
+    ljam();
+    dynClearBit((Uint32 *)bm_ptr, pos);
     req_struct->in_buf_index= newIndex;
     return true;
   } else {

--- 1.155/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp	2006-11-09 11:08:55 +01:00
+++ 1.156/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp	2006-11-09 11:08:55 +01:00
@@ -2410,6 +2410,7 @@ NdbDictInterface::compChangeMask(const N
     We can add one or more new columns at the end, with some restrictions:
      - All existing columns must be unchanged.
      - The new column must be dynamic.
+     - The new column must be nullable.
      - The new column must be memory based.
      - The new column can not be a primary key or distribution key.
      - There must already be at least one existing memory-stored dynamic or
@@ -2434,7 +2435,7 @@ NdbDictInterface::compChangeMask(const N
     for(Uint32 i=old_sz; i<sz; i++)
     {
       const NdbColumnImpl *col= impl.m_columns[i];
-      if(!col->m_dynamic ||
+      if(!col->m_dynamic || !col->m_nullable ||
          col->m_storageType == NDB_STORAGETYPE_DISK ||
          col->m_pk ||
          col->m_distributionKey ||

--- 1.23/storage/ndb/test/src/NDBT_Tables.cpp	2006-11-09 11:08:55 +01:00
+++ 1.24/storage/ndb/test/src/NDBT_Tables.cpp	2006-11-09 11:08:55 +01:00
@@ -302,7 +302,6 @@ NDBT_Table T14("T14", sizeof(T14Attribs)
   Test many different combinations of attribute types, sizes, and NULLability.
   Also exersize >32bit dynattr bitmap.
 */
-// pk nullable cs mm/dd dyn
 static
 const
 NDBT_Attribute T15Attribs[] = {
@@ -338,6 +337,10 @@ NDBT_Attribute T15Attribs[] = {
   NDBT_Attribute("KOL30", NdbDictionary::Column::Char, 4, false, true, 0, DD),
   NDBT_Attribute("KOL31", NdbDictionary::Column::Char, 4, false, false, 0, MM, true),
   NDBT_Attribute("KOL32", NdbDictionary::Column::Varbinary, 4, false, false, 0, MM, true),
+  NDBT_Attribute("BIT1", NdbDictionary::Column::Bit, 27, false, true, 0, MM, true),
+  NDBT_Attribute("BIT2", NdbDictionary::Column::Bit, 1, false, false, 0, MM, true),
+  NDBT_Attribute("BIT3", NdbDictionary::Column::Bit, 1, false, true, 0, MM, true),
+  NDBT_Attribute("BIT4", NdbDictionary::Column::Bit, 8, false, false, 0, MM, true),
   NDBT_Attribute("KOL33", NdbDictionary::Column::Char, 4, false, false, 0, MM, true),
   NDBT_Attribute("KOL34", NdbDictionary::Column::Varbinary, 4, false, false, 0, MM, true),
   NDBT_Attribute("KOL35", NdbDictionary::Column::Char, 4, false, false, 0, MM, true),
@@ -363,55 +366,18 @@ static
 const
 NDBT_Table T15("T15", sizeof(T15Attribs)/sizeof(NDBT_Attribute), T15Attribs);
 
+/* Test dynamic bit types when no other varsize/dynamic. */
 static
 const
-NDBT_Attribute T15AAttribs[] = {
-  NDBT_Attribute("KOL1", NdbDictionary::Column::Unsigned, 1, true, false, 0, MM, true),
-  NDBT_Attribute("KOL2", NdbDictionary::Column::Varbinary, 100, false, true, 0, MM, true),
-  NDBT_Attribute("KOL3", NdbDictionary::Column::Unsigned, 1, false, true, 0, MM, true),
-  NDBT_Attribute("KOL4", NdbDictionary::Column::Int, 1, false, false, 0, MM, true),
-  NDBT_Attribute("KOL5", NdbDictionary::Column::Float, 1, false, true, 0, MM, true),
-  NDBT_Attribute("KOL6", NdbDictionary::Column::Char, 4, false, true, 0, MM, true),
-  NDBT_Attribute("KOL7", NdbDictionary::Column::Varbinary, 4, false, true, 0, MM, true),
-  NDBT_Attribute("KOL8", NdbDictionary::Column::Char, 4, false, true, 0, MM, true),
-  NDBT_Attribute("KOL9", NdbDictionary::Column::Varbinary, 4, false, true, 0, MM, true),
-  NDBT_Attribute("KOL10", NdbDictionary::Column::Char, 4, false, true, 0, MM, true),
-  NDBT_Attribute("KOL11", NdbDictionary::Column::Varbinary, 4, false, true, 0, MM, true),
-  NDBT_Attribute("KOL12", NdbDictionary::Column::Char, 4, false, true, 0, MM, true),
-  NDBT_Attribute("KOL13", NdbDictionary::Column::Varbinary, 4, false, true, 0, MM, true),
-  NDBT_Attribute("KOL14", NdbDictionary::Column::Char, 4, false, true, 0, MM, true),
-  NDBT_Attribute("KOL15", NdbDictionary::Column::Varbinary, 4, false, true, 0, MM, true),
-  NDBT_Attribute("KOL16", NdbDictionary::Column::Char, 4, false, true, 0, MM, true),
-  NDBT_Attribute("KOL17", NdbDictionary::Column::Varbinary, 4, false, true, 0, MM, true),
-  NDBT_Attribute("KOL18", NdbDictionary::Column::Char, 4, false, true, 0, MM, true),
-  NDBT_Attribute("KOL19", NdbDictionary::Column::Varbinary, 4, false, true, 0, MM, true),
-  NDBT_Attribute("KOL20", NdbDictionary::Column::Char, 4, false, true, 0, MM, true),
-  NDBT_Attribute("KOL21", NdbDictionary::Column::Varbinary, 4, false, true, 0, MM, true),
-  NDBT_Attribute("KOL30", NdbDictionary::Column::Char, 4, false, true, 0, DD),
-  NDBT_Attribute("KOL33", NdbDictionary::Column::Char, 4, false, false, 0, MM, true),
-  NDBT_Attribute("KOL34", NdbDictionary::Column::Varbinary, 4, false, false, 0, MM, true),
-  NDBT_Attribute("KOL35", NdbDictionary::Column::Char, 4, false, false, 0, MM, true),
-  NDBT_Attribute("KOL36", NdbDictionary::Column::Varbinary, 4, false, false, 0, MM, true),
-  NDBT_Attribute("KOL37", NdbDictionary::Column::Char, 4, false, false, 0, MM, true),
-  NDBT_Attribute("KOL38", NdbDictionary::Column::Varbinary, 4, false, false, 0, MM, true),
-  NDBT_Attribute("KOL39", NdbDictionary::Column::Char, 4, false, false, 0, MM, true),
-  NDBT_Attribute("KOL40", NdbDictionary::Column::Varbinary, 4, false, false, 0, MM, true),
-  NDBT_Attribute("KOL41", NdbDictionary::Column::Char, 64, false, true, 0, MM, true),
-  NDBT_Attribute("KOL42", NdbDictionary::Column::Char, 4, false, true, 0, MM, true),
-  NDBT_Attribute("KOL43", NdbDictionary::Column::Char, 8, false, true, 0, MM, true),
-  NDBT_Attribute("KOL44", NdbDictionary::Column::Char, 27, false, true, 0, MM, true),
-  NDBT_Attribute("KOL45", NdbDictionary::Column::Char, 64, false, false, 0, MM, true),
-  NDBT_Attribute("KOL46", NdbDictionary::Column::Char, 4, false, false, 0, MM, true),
-  NDBT_Attribute("KOL47", NdbDictionary::Column::Char, 8, false, false, 0, MM, true),
-  NDBT_Attribute("KOL48", NdbDictionary::Column::Char, 27, false, false, 0, MM, true),
-  NDBT_Attribute("KOL49", NdbDictionary::Column::Varbinary, 255, false, false, 0, MM, true),
-  /* This one is for update count, needed by hugoScanUpdate. */
-  NDBT_Attribute("KOL99", NdbDictionary::Column::Unsigned, 1, false, false, 0, MM, true),
+NDBT_Attribute T16Attribs[] = {
+  NDBT_Attribute("KOL1", NdbDictionary::Column::Unsigned, 1, true, false),
+  NDBT_Attribute("Kol2", NdbDictionary::Column::Bit, 27, false, true, 0, MM, true),
+  NDBT_Attribute("KOL99", NdbDictionary::Column::Unsigned, 1, false, false),
 };
 
 static
 const
-NDBT_Table T15A("T15A", sizeof(T15AAttribs)/sizeof(NDBT_Attribute), T15AAttribs);
+NDBT_Table T16("T16", sizeof(T16Attribs)/sizeof(NDBT_Attribute), T16Attribs);
 
 /*
   C2 DHCP TABLES, MAYBE THESE SHOULD BE MOVED TO THE UTIL_TABLES?
@@ -553,7 +519,7 @@ NDBT_Table *test_tables[]=
   &T13,
   &T14,
   &T15,
-  &T15A,
+  &T16,
   &I1,
   &I2,
   &I3,

--- 1.367/sql/ha_ndbcluster.cc	2006-11-09 11:08:55 +01:00
+++ 1.368/sql/ha_ndbcluster.cc	2006-11-09 11:08:55 +01:00
@@ -4710,6 +4710,9 @@ int ha_ndbcluster::create(const char *na
     else
       col.setStorageType(NdbDictionary::Column::StorageTypeMemory);
 
+    col.setDynamic(info->row_type==ROW_TYPE_DYNAMIC);
+    // col.setDynamic(true); // For testing dynattr
+
     tab.addColumn(col);
     if (col.getPrimaryKey())
       pk_length += (field->pack_length() + 3) / 4;
Thread
bk commit into 5.1 tree (knielsen:1.2330)knielsen9 Nov