/* Copyright (C) 2003 MySQL AB

   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; either version 2 of the License, or
   (at your option) any later version.

   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 <ndb_global.h>
#include <my_sys.h>

#define DBDICT_C
#include "Dbdict.hpp"

#include <ndb_limits.h>
#include <NdbOut.hpp>
#include <Properties.hpp>
#include <Configuration.hpp>
#include <SectionReader.hpp>
#include <SimpleProperties.hpp>
#include <AttributeHeader.hpp>
#include <signaldata/DictSchemaInfo.hpp>
#include <signaldata/DictTabInfo.hpp>
#include <signaldata/DropTabFile.hpp>

#include <signaldata/EventReport.hpp>
#include <signaldata/FsCloseReq.hpp>
#include <signaldata/FsConf.hpp>
#include <signaldata/FsOpenReq.hpp>
#include <signaldata/FsReadWriteReq.hpp>
#include <signaldata/FsRef.hpp>
#include <signaldata/GetTabInfo.hpp>
#include <signaldata/GetTableId.hpp>
#include <signaldata/HotSpareRep.hpp>
#include <signaldata/NFCompleteRep.hpp>
#include <signaldata/NodeFailRep.hpp>
#include <signaldata/ReadNodesConf.hpp>
#include <signaldata/RelTabMem.hpp>
#include <signaldata/WaitGCP.hpp>
#include <signaldata/ListTables.hpp>

#include <signaldata/CreateTrig.hpp>
#include <signaldata/AlterTrig.hpp>
#include <signaldata/DropTrig.hpp>
#include <signaldata/CreateIndx.hpp>
#include <signaldata/DropIndx.hpp>
#include <signaldata/BuildIndx.hpp>

#include <signaldata/CreateEvnt.hpp>
#include <signaldata/UtilPrepare.hpp>
#include <signaldata/UtilExecute.hpp>
#include <signaldata/UtilRelease.hpp>
#include <signaldata/SumaImpl.hpp> 
#include <GrepError.hpp>
//#include <signaldata/DropEvnt.hpp>

#include <signaldata/LqhFrag.hpp>

#include <signaldata/DiAddTab.hpp>
#include <signaldata/DihStartTab.hpp>

#include <signaldata/DropTable.hpp>
#include <signaldata/DropTab.hpp>
#include <signaldata/PrepDropTab.hpp>

#include <signaldata/CreateTable.hpp>
#include <signaldata/AlterTable.hpp>
#include <signaldata/AlterTab.hpp>
#include <signaldata/CreateFragmentation.hpp>
#include <signaldata/CreateTab.hpp>
#include <NdbSleep.h>

#define ZNOT_FOUND 626
#define ZALREADYEXIST 630

//#define EVENT_PH2_DEBUG
//#define EVENT_PH3_DEBUG
//#define EVENT_DEBUG

#define EVENT_TRACE \
//  ndbout_c("Event debug trace: File: %s Line: %u", __FILE__, __LINE__)

#define DIV(x,y) (((x)+(y)-1)/(y))
#include <ndb_version.h>

/* **************************************************************** */
/* ---------------------------------------------------------------- */
/* MODULE:          GENERAL MODULE -------------------------------- */
/* ---------------------------------------------------------------- */
/*                                                                  */
/* This module contains general stuff. Mostly debug signals and     */
/* general signals that go into a specific module after checking a  */
/* state variable. Also general subroutines used by many.           */
/* ---------------------------------------------------------------- */
/* **************************************************************** */

/* ---------------------------------------------------------------- */
// This signal is used to dump states of various variables in the
// block by command.
/* ---------------------------------------------------------------- */
void
Dbdict::execDUMP_STATE_ORD(Signal* signal)
{
  jamEntry();

#ifdef VM_TRACE
  if(signal->theData[0] == 1222){
    const Uint32 tab = signal->theData[1];
    PrepDropTabReq* req = (PrepDropTabReq*)signal->getDataPtr();
    req->senderRef = reference();
    req->senderData = 1222;
    req->tableId = tab;
    sendSignal(DBLQH_REF, GSN_PREP_DROP_TAB_REQ, signal,
	       PrepDropTabReq::SignalLength, JBB);
  }

  if(signal->theData[0] == 1223){
    const Uint32 tab = signal->theData[1];
    PrepDropTabReq* req = (PrepDropTabReq*)signal->getDataPtr();
    req->senderRef = reference();
    req->senderData = 1222;
    req->tableId = tab;
    sendSignal(DBTC_REF, GSN_PREP_DROP_TAB_REQ, signal,
	       PrepDropTabReq::SignalLength, JBB);
  }

  if(signal->theData[0] == 1224){
    const Uint32 tab = signal->theData[1];
    PrepDropTabReq* req = (PrepDropTabReq*)signal->getDataPtr();
    req->senderRef = reference();
    req->senderData = 1222;
    req->tableId = tab;
    sendSignal(DBDIH_REF, GSN_PREP_DROP_TAB_REQ, signal,
	       PrepDropTabReq::SignalLength, JBB);
  }

  if(signal->theData[0] == 1225){
    const Uint32 tab = signal->theData[1];
    const Uint32 ver = signal->theData[2];
    TableRecordPtr tabRecPtr;
    c_tableRecordPool.getPtr(tabRecPtr, tab);
    DropTableReq * req = (DropTableReq*)signal->getDataPtr();
    req->senderData = 1225;
    req->senderRef = numberToRef(1,1);
    req->tableId = tab;
    req->tableVersion = tabRecPtr.p->tableVersion + ver;
    sendSignal(DBDICT_REF, GSN_DROP_TABLE_REQ, signal,
	       DropTableReq::SignalLength, JBB);
  }
#endif  
  
  return;
}//Dbdict::execDUMP_STATE_ORD()

/* ---------------------------------------------------------------- */
/* ---------------------------------------------------------------- */
// CONTINUEB is used when a real-time break is needed for long
// processes.
/* ---------------------------------------------------------------- */
/* ---------------------------------------------------------------- */
void Dbdict::execCONTINUEB(Signal* signal) 
{
  jamEntry();
  switch (signal->theData[0]) {
  case ZPACK_TABLE_INTO_PAGES :
    jam();
    packTableIntoPages(signal, signal->theData[1], signal->theData[2]);
    break;

  case ZSEND_GET_TAB_RESPONSE :
    jam();
    sendGetTabResponse(signal);
    break;

  default :
    ndbrequire(false);
    break;
  }//switch
  return;
}//execCONTINUEB()

/* ---------------------------------------------------------------- */
/* ---------------------------------------------------------------- */
// Routine to handle pack table into pages.
/* ---------------------------------------------------------------- */
/* ---------------------------------------------------------------- */

void Dbdict::packTableIntoPages(Signal* signal, Uint32 tableId, Uint32 pageId)
{

  PageRecordPtr pagePtr;
  TableRecordPtr tablePtr;
  c_pageRecordArray.getPtr(pagePtr, pageId);
  
  memset(&pagePtr.p->word[0], 0, 4 * ZPAGE_HEADER_SIZE);
  c_tableRecordPool.getPtr(tablePtr, tableId);
  LinearWriter w(&pagePtr.p->word[ZPAGE_HEADER_SIZE], 
		 8 * ZSIZE_OF_PAGES_IN_WORDS);

  w.first();
  packTableIntoPagesImpl(w, tablePtr, signal);
    
  Uint32 wordsOfTable = w.getWordsUsed();
  Uint32 pagesUsed = 
    DIV(wordsOfTable + ZPAGE_HEADER_SIZE, ZSIZE_OF_PAGES_IN_WORDS);
  pagePtr.p->word[ZPOS_CHECKSUM] = 
    computeChecksum(&pagePtr.p->word[0], pagesUsed * ZSIZE_OF_PAGES_IN_WORDS);
  
  switch (c_packTable.m_state) {
  case PackTable::PTS_IDLE:
  case PackTable::PTS_ADD_TABLE_MASTER:
  case PackTable::PTS_ADD_TABLE_SLAVE:
  case PackTable::PTS_RESTART:
    ndbrequire(false);
    break;
  case PackTable::PTS_GET_TAB:
    jam();
    c_retrieveRecord.retrievedNoOfPages = pagesUsed;
    c_retrieveRecord.retrievedNoOfWords = wordsOfTable;
    sendGetTabResponse(signal);
    return;
    break;
  }//switch
  ndbrequire(false);
  return;
}//packTableIntoPages()

void
Dbdict::packTableIntoPagesImpl(SimpleProperties::Writer & w,
			       TableRecordPtr tablePtr,
			       Signal* signal){
  
  w.add(DictTabInfo::TableName, tablePtr.p->tableName);
  w.add(DictTabInfo::TableId, tablePtr.i);
#ifdef HAVE_TABLE_REORG
  w.add(DictTabInfo::SecondTableId, tablePtr.p->secondTable);
#else
  w.add(DictTabInfo::SecondTableId, (Uint32)0);
#endif
  w.add(DictTabInfo::TableVersion, tablePtr.p->tableVersion);
  w.add(DictTabInfo::NoOfKeyAttr, tablePtr.p->noOfPrimkey);
  w.add(DictTabInfo::NoOfAttributes, tablePtr.p->noOfAttributes);
  w.add(DictTabInfo::NoOfNullable, tablePtr.p->noOfNullAttr);
  w.add(DictTabInfo::NoOfVariable, (Uint32)0);
  w.add(DictTabInfo::KeyLength, tablePtr.p->tupKeyLength);
  
  w.add(DictTabInfo::TableLoggedFlag, tablePtr.p->storedTable);
  w.add(DictTabInfo::MinLoadFactor, tablePtr.p->minLoadFactor);
  w.add(DictTabInfo::MaxLoadFactor, tablePtr.p->maxLoadFactor);
  w.add(DictTabInfo::TableKValue, tablePtr.p->kValue);
  w.add(DictTabInfo::FragmentTypeVal, tablePtr.p->fragmentType);
  w.add(DictTabInfo::TableTypeVal, tablePtr.p->tableType);
  
  if(!signal)
  {
    w.add(DictTabInfo::FragmentCount, tablePtr.p->fragmentCount);
  }
  else
  {
    Uint32 * theData = signal->getDataPtrSend();
    CreateFragmentationReq * const req = (CreateFragmentationReq*)theData;
    req->senderRef = 0;
    req->senderData = RNIL;
    req->fragmentationType = tablePtr.p->fragmentType;
    req->noOfFragments = 0;
    req->fragmentNode = 0;
    req->primaryTableId = tablePtr.i;
    EXECUTE_DIRECT(DBDIH, GSN_CREATE_FRAGMENTATION_REQ, signal,
		   CreateFragmentationReq::SignalLength);
    if(signal->theData[0] == 0)
    {
      Uint16 *data = (Uint16*)&signal->theData[25];
      Uint32 count = 2 + data[0] * data[1];
      w.add(DictTabInfo::FragmentDataLen, 2*count);
      w.add(DictTabInfo::FragmentData, data, 2*count);
    }
  }
  
  if (tablePtr.p->primaryTableId != RNIL){
    TableRecordPtr primTab;
    c_tableRecordPool.getPtr(primTab, tablePtr.p->primaryTableId);
    w.add(DictTabInfo::PrimaryTable, primTab.p->tableName);
    w.add(DictTabInfo::PrimaryTableId, tablePtr.p->primaryTableId);
    w.add(DictTabInfo::IndexState, tablePtr.p->indexState);
    w.add(DictTabInfo::InsertTriggerId, tablePtr.p->insertTriggerId);
    w.add(DictTabInfo::UpdateTriggerId, tablePtr.p->updateTriggerId);
    w.add(DictTabInfo::DeleteTriggerId, tablePtr.p->deleteTriggerId);
    w.add(DictTabInfo::CustomTriggerId, tablePtr.p->customTriggerId);
  }
  w.add(DictTabInfo::FrmLen, tablePtr.p->frmLen);
  w.add(DictTabInfo::FrmData, tablePtr.p->frmData, tablePtr.p->frmLen);
  
  Uint32 nextAttribute = tablePtr.p->firstAttribute;
  AttributeRecordPtr attrPtr;
  do {
    jam();
    c_attributeRecordPool.getPtr(attrPtr, nextAttribute);
    
    w.add(DictTabInfo::AttributeName, attrPtr.p->attributeName);
    w.add(DictTabInfo::AttributeId, attrPtr.p->attributeId);
    w.add(DictTabInfo::AttributeKeyFlag, attrPtr.p->tupleKey > 0);
    
    const Uint32 desc = attrPtr.p->attributeDescriptor;
    const Uint32 attrType = AttributeDescriptor::getType(desc);
    const Uint32 attrSize = AttributeDescriptor::getSize(desc);
    const Uint32 arraySize = AttributeDescriptor::getArraySize(desc);
    const Uint32 nullable = AttributeDescriptor::getNullable(desc);
    const Uint32 DKey = AttributeDescriptor::getDKey(desc);

    // AttributeType deprecated
    w.add(DictTabInfo::AttributeSize, attrSize);
    w.add(DictTabInfo::AttributeArraySize, arraySize);
    w.add(DictTabInfo::AttributeNullableFlag, nullable);
    w.add(DictTabInfo::AttributeDKey, DKey);
    w.add(DictTabInfo::AttributeExtType, attrType);
    w.add(DictTabInfo::AttributeExtPrecision, attrPtr.p->extPrecision);
    w.add(DictTabInfo::AttributeExtScale, attrPtr.p->extScale);
    w.add(DictTabInfo::AttributeExtLength, attrPtr.p->extLength);
    w.add(DictTabInfo::AttributeAutoIncrement, 
	  (Uint32)attrPtr.p->autoIncrement);
    w.add(DictTabInfo::AttributeDefaultValue, attrPtr.p->defaultValue);
    
    w.add(DictTabInfo::AttributeEnd, 1);
    nextAttribute = attrPtr.p->nextAttrInTable;
  } while (nextAttribute != RNIL);
  
  w.add(DictTabInfo::TableEnd, 1);
}

/* ---------------------------------------------------------------- */
/* ---------------------------------------------------------------- */
// The routines to handle responses from file system.
/* ---------------------------------------------------------------- */
/* ---------------------------------------------------------------- */

/* ---------------------------------------------------------------- */
// A file was successfully closed.
/* ---------------------------------------------------------------- */
void Dbdict::execFSCLOSECONF(Signal* signal) 
{
  FsConnectRecordPtr fsPtr;
  FsConf * const fsConf = (FsConf *)&signal->theData[0];
  jamEntry();
  c_fsConnectRecordPool.getPtr(fsPtr, fsConf->userPointer);
  switch (fsPtr.p->fsState) {
  case FsConnectRecord::CLOSE_WRITE_SCHEMA:
    jam();
    closeWriteSchemaConf(signal, fsPtr);
    break;
  case FsConnectRecord::CLOSE_READ_SCHEMA:
    jam();
    closeReadSchemaConf(signal, fsPtr);
    break;
  case FsConnectRecord::CLOSE_READ_TAB_FILE:
    jam();
    closeReadTableConf(signal, fsPtr);
    break;
  case FsConnectRecord::CLOSE_WRITE_TAB_FILE:
    jam();
    closeWriteTableConf(signal, fsPtr);
    break;
  default:
    jamLine((fsPtr.p->fsState & 0xFFF));
    ndbrequire(false);
    break;
  }//switch
}//execFSCLOSECONF()

/* ---------------------------------------------------------------- */
// A close file was refused.
/* ---------------------------------------------------------------- */
void Dbdict::execFSCLOSEREF(Signal* signal) 
{
  jamEntry();
  progError(0, 0);
}//execFSCLOSEREF()

/* ---------------------------------------------------------------- */
// A file was successfully opened.
/* ---------------------------------------------------------------- */
void Dbdict::execFSOPENCONF(Signal* signal) 
{
  FsConnectRecordPtr fsPtr;
  jamEntry();
  FsConf * const fsConf = (FsConf *)&signal->theData[0];
  c_fsConnectRecordPool.getPtr(fsPtr, fsConf->userPointer);

  Uint32 filePointer = fsConf->filePointer;
  fsPtr.p->filePtr = filePointer;
  switch (fsPtr.p->fsState) {
  case FsConnectRecord::OPEN_WRITE_SCHEMA:
    jam();
    fsPtr.p->fsState = FsConnectRecord::WRITE_SCHEMA;
    writeSchemaFile(signal, filePointer, fsPtr.i);
    break;
  case FsConnectRecord::OPEN_READ_SCHEMA1:
    jam();
    fsPtr.p->fsState = FsConnectRecord::READ_SCHEMA1;
    readSchemaFile(signal, filePointer, fsPtr.i);
    break;
  case FsConnectRecord::OPEN_READ_SCHEMA2:
    jam();
    fsPtr.p->fsState = FsConnectRecord::READ_SCHEMA2;
    readSchemaFile(signal, filePointer, fsPtr.i);
    break;
  case FsConnectRecord::OPEN_READ_TAB_FILE1:
    jam();
    fsPtr.p->fsState = FsConnectRecord::READ_TAB_FILE1;
    readTableFile(signal, filePointer, fsPtr.i);
    break;
  case FsConnectRecord::OPEN_READ_TAB_FILE2:
    jam();
    fsPtr.p->fsState = FsConnectRecord::READ_TAB_FILE2;
    readTableFile(signal, filePointer, fsPtr.i);
    break;
  case FsConnectRecord::OPEN_WRITE_TAB_FILE:
    jam();
    fsPtr.p->fsState = FsConnectRecord::WRITE_TAB_FILE;
    writeTableFile(signal, filePointer, fsPtr.i);
    break;
  default:
    jamLine((fsPtr.p->fsState & 0xFFF));
    ndbrequire(false);
    break;
  }//switch
}//execFSOPENCONF()

/* ---------------------------------------------------------------- */
// An open file was refused.
/* ---------------------------------------------------------------- */
void Dbdict::execFSOPENREF(Signal* signal) 
{
  jamEntry();
  FsRef * const fsRef = (FsRef *)&signal->theData[0];
  FsConnectRecordPtr fsPtr;
  c_fsConnectRecordPool.getPtr(fsPtr, fsRef->userPointer);
  switch (fsPtr.p->fsState) {
  case FsConnectRecord::OPEN_READ_SCHEMA1:
    openReadSchemaRef(signal, fsPtr);
    break;
  case FsConnectRecord::OPEN_READ_TAB_FILE1:
    jam();
    openReadTableRef(signal, fsPtr);
    break;
  default:
    jamLine((fsPtr.p->fsState & 0xFFF));
    ndbrequire(false);
    break;
  }//switch
}//execFSOPENREF()

/* ---------------------------------------------------------------- */
// A file was successfully read.
/* ---------------------------------------------------------------- */
void Dbdict::execFSREADCONF(Signal* signal) 
{
  jamEntry();
  FsConf * const fsConf = (FsConf *)&signal->theData[0];
  FsConnectRecordPtr fsPtr;
  c_fsConnectRecordPool.getPtr(fsPtr, fsConf->userPointer);
  switch (fsPtr.p->fsState) {
  case FsConnectRecord::READ_SCHEMA1:
  case FsConnectRecord::READ_SCHEMA2:
    readSchemaConf(signal ,fsPtr);
    break;
  case FsConnectRecord::READ_TAB_FILE1:
  case FsConnectRecord::READ_TAB_FILE2:
    jam();
    readTableConf(signal ,fsPtr);
    break;
  default:
    jamLine((fsPtr.p->fsState & 0xFFF));
    ndbrequire(false);
    break;
  }//switch
}//execFSREADCONF()

/* ---------------------------------------------------------------- */
// A read file was refused.
/* ---------------------------------------------------------------- */
void Dbdict::execFSREADREF(Signal* signal) 
{
  jamEntry();
  FsRef * const fsRef = (FsRef *)&signal->theData[0];
  FsConnectRecordPtr fsPtr;
  c_fsConnectRecordPool.getPtr(fsPtr, fsRef->userPointer);
  switch (fsPtr.p->fsState) {
  case FsConnectRecord::READ_SCHEMA1:
    readSchemaRef(signal, fsPtr);
    break;
  case FsConnectRecord::READ_TAB_FILE1:
    jam();
    readTableRef(signal, fsPtr);
    break;
  default:
    jamLine((fsPtr.p->fsState & 0xFFF));
    ndbrequire(false);
    break;
  }//switch
}//execFSREADREF()

/* ---------------------------------------------------------------- */
// A file was successfully written.
/* ---------------------------------------------------------------- */
void Dbdict::execFSWRITECONF(Signal* signal) 
{
  FsConf * const fsConf = (FsConf *)&signal->theData[0];
  FsConnectRecordPtr fsPtr;
  jamEntry();
  c_fsConnectRecordPool.getPtr(fsPtr, fsConf->userPointer);
  switch (fsPtr.p->fsState) {
  case FsConnectRecord::WRITE_TAB_FILE:
    writeTableConf(signal, fsPtr);
    break;
  case FsConnectRecord::WRITE_SCHEMA:
    jam();
    writeSchemaConf(signal, fsPtr);
    break;
  default:
    jamLine((fsPtr.p->fsState & 0xFFF));
    ndbrequire(false);
    break;
  }//switch
}//execFSWRITECONF()

/* ---------------------------------------------------------------- */
// A write file was refused.
/* ---------------------------------------------------------------- */
void Dbdict::execFSWRITEREF(Signal* signal) 
{
  jamEntry();
  progError(0, 0);
}//execFSWRITEREF()

/* ---------------------------------------------------------------- */
// Routines to handle Read/Write of Table Files
/* ---------------------------------------------------------------- */
void
Dbdict::writeTableFile(Signal* signal, Uint32 tableId, 
		       SegmentedSectionPtr tabInfoPtr, Callback* callback){
  
  ndbrequire(c_writeTableRecord.tableWriteState == WriteTableRecord::IDLE);
  
  Uint32 sz = tabInfoPtr.sz + ZPAGE_HEADER_SIZE;

  c_writeTableRecord.noOfPages = DIV(sz, ZSIZE_OF_PAGES_IN_WORDS);
  c_writeTableRecord.tableWriteState = WriteTableRecord::TWR_CALLBACK;
  c_writeTableRecord.m_callback = * callback;

  c_writeTableRecord.pageId = 0;
  ndbrequire(c_writeTableRecord.noOfPages < 8);

  PageRecordPtr pageRecPtr;
  c_pageRecordArray.getPtr(pageRecPtr, c_writeTableRecord.pageId);
  copy(&pageRecPtr.p->word[ZPAGE_HEADER_SIZE], tabInfoPtr);
  
  memset(&pageRecPtr.p->word[0], 0, 4 * ZPAGE_HEADER_SIZE);
  pageRecPtr.p->word[ZPOS_CHECKSUM] = 
    computeChecksum(&pageRecPtr.p->word[0], 
		    c_writeTableRecord.noOfPages * ZSIZE_OF_PAGES_IN_WORDS);
  
  startWriteTableFile(signal, tableId);

}

void Dbdict::startWriteTableFile(Signal* signal, Uint32 tableId)
{
  FsConnectRecordPtr fsPtr;
  c_writeTableRecord.tableId = tableId;
  c_fsConnectRecordPool.getPtr(fsPtr, getFsConnRecord());
  fsPtr.p->fsState = FsConnectRecord::OPEN_WRITE_TAB_FILE;
  openTableFile(signal, 0, fsPtr.i, tableId, true);
  c_writeTableRecord.noOfTableFilesHandled = 0;
}//Dbdict::startWriteTableFile()

void Dbdict::openTableFile(Signal* signal,
                           Uint32 fileNo,
                           Uint32 fsConPtr,
                           Uint32 tableId,
                           bool   writeFlag) 
{
  TableRecordPtr tablePtr;
  FsOpenReq * const fsOpenReq = (FsOpenReq *)&signal->theData[0];
  c_tableRecordPool.getPtr(tablePtr, tableId);

  fsOpenReq->userReference = reference();
  fsOpenReq->userPointer = fsConPtr;
  if (writeFlag) {
    jam();
    fsOpenReq->fileFlags = 
      FsOpenReq::OM_WRITEONLY | 
      FsOpenReq::OM_TRUNCATE | 
      FsOpenReq::OM_CREATE | 
      FsOpenReq::OM_SYNC;
  } else {
    jam();
    fsOpenReq->fileFlags = FsOpenReq::OM_READONLY;
  }//if
  ndbrequire(tablePtr.p->tableVersion < ZNIL);
  fsOpenReq->fileNumber[3] = 0; // Initialise before byte changes
  FsOpenReq::setVersion(fsOpenReq->fileNumber, 1);
  FsOpenReq::setSuffix(fsOpenReq->fileNumber, FsOpenReq::S_TABLELIST);
  FsOpenReq::v1_setDisk(fsOpenReq->fileNumber, (fileNo + 1));
  FsOpenReq::v1_setTable(fsOpenReq->fileNumber, tableId);
  FsOpenReq::v1_setFragment(fsOpenReq->fileNumber, (Uint32)-1);
  FsOpenReq::v1_setS(fsOpenReq->fileNumber, tablePtr.p->tableVersion);
  FsOpenReq::v1_setP(fsOpenReq->fileNumber, 255);
/* ---------------------------------------------------------------- */
// File name : D1/DBDICT/T0/S1.TableList
// D1 means Disk 1 (set by fileNo + 1)
// T0 means table id = 0
// S1 means tableVersion 1
// TableList indicates that this is a file for a table description.
/* ---------------------------------------------------------------- */
  sendSignal(NDBFS_REF, GSN_FSOPENREQ, signal, FsOpenReq::SignalLength, JBA);
}//openTableFile()

void Dbdict::writeTableFile(Signal* signal, Uint32 filePtr, Uint32 fsConPtr) 
{
  FsReadWriteReq * const fsRWReq = (FsReadWriteReq *)&signal->theData[0];

  fsRWReq->filePointer = filePtr;
  fsRWReq->userReference = reference();
  fsRWReq->userPointer = fsConPtr;
  fsRWReq->operationFlag = 0; // Initialise before bit changes
  FsReadWriteReq::setSyncFlag(fsRWReq->operationFlag, 1);
  FsReadWriteReq::setFormatFlag(fsRWReq->operationFlag, 
                                FsReadWriteReq::fsFormatArrayOfPages);
  fsRWReq->varIndex = ZALLOCATE;
  fsRWReq->numberOfPages = c_writeTableRecord.noOfPages;
  fsRWReq->data.arrayOfPages.varIndex = c_writeTableRecord.pageId;
  fsRWReq->data.arrayOfPages.fileOffset = 0; // Write to file page 0
  sendSignal(NDBFS_REF, GSN_FSWRITEREQ, signal, 8, JBA);
}//writeTableFile()

void Dbdict::writeTableConf(Signal* signal,
                                FsConnectRecordPtr fsPtr)
{
  fsPtr.p->fsState = FsConnectRecord::CLOSE_WRITE_TAB_FILE;
  closeFile(signal, fsPtr.p->filePtr, fsPtr.i);
  return;
}//Dbdict::writeTableConf()

void Dbdict::closeWriteTableConf(Signal* signal,
                                 FsConnectRecordPtr fsPtr)
{
  c_writeTableRecord.noOfTableFilesHandled++;
  if (c_writeTableRecord.noOfTableFilesHandled < 2) {
    jam();
    fsPtr.p->fsState = FsConnectRecord::OPEN_WRITE_TAB_FILE;
    openTableFile(signal, 1, fsPtr.i, c_writeTableRecord.tableId, true);
    return;
  } 
  ndbrequire(c_writeTableRecord.noOfTableFilesHandled == 2);
  c_fsConnectRecordPool.release(fsPtr);
  WriteTableRecord::TableWriteState state = c_writeTableRecord.tableWriteState;
  c_writeTableRecord.tableWriteState = WriteTableRecord::IDLE;
  switch (state) {
  case WriteTableRecord::IDLE:
  case WriteTableRecord::WRITE_ADD_TABLE_MASTER :
  case WriteTableRecord::WRITE_ADD_TABLE_SLAVE :
  case WriteTableRecord::WRITE_RESTART_FROM_MASTER :
  case WriteTableRecord::WRITE_RESTART_FROM_OWN :
    ndbrequire(false);
    break;
  case WriteTableRecord::TWR_CALLBACK:
    jam();
    execute(signal, c_writeTableRecord.m_callback, 0);
    return;
  }
  ndbrequire(false);
}//Dbdict::closeWriteTableConf()

void Dbdict::startReadTableFile(Signal* signal, Uint32 tableId)
{
  //globalSignalLoggers.log(number(), "startReadTableFile");
  ndbrequire(!c_readTableRecord.inUse);
  
  FsConnectRecordPtr fsPtr;
  c_fsConnectRecordPool.getPtr(fsPtr, getFsConnRecord());
  c_readTableRecord.inUse = true;
  c_readTableRecord.tableId = tableId;
  fsPtr.p->fsState = FsConnectRecord::OPEN_READ_TAB_FILE1;
  openTableFile(signal, 0, fsPtr.i, tableId, false);
}//Dbdict::startReadTableFile()

void Dbdict::openReadTableRef(Signal* signal,
                              FsConnectRecordPtr fsPtr) 
{
  fsPtr.p->fsState = FsConnectRecord::OPEN_READ_TAB_FILE2;
  openTableFile(signal, 1, fsPtr.i, c_readTableRecord.tableId, false);
  return;
}//Dbdict::openReadTableConf()

void Dbdict::readTableFile(Signal* signal, Uint32 filePtr, Uint32 fsConPtr) 
{
  FsReadWriteReq * const fsRWReq = (FsReadWriteReq *)&signal->theData[0];

  fsRWReq->filePointer = filePtr;
  fsRWReq->userReference = reference();
  fsRWReq->userPointer = fsConPtr;
  fsRWReq->operationFlag = 0; // Initialise before bit changes
  FsReadWriteReq::setSyncFlag(fsRWReq->operationFlag, 0);
  FsReadWriteReq::setFormatFlag(fsRWReq->operationFlag, 
                                FsReadWriteReq::fsFormatArrayOfPages);
  fsRWReq->varIndex = ZALLOCATE;
  fsRWReq->numberOfPages = c_readTableRecord.noOfPages;
  fsRWReq->data.arrayOfPages.varIndex = c_readTableRecord.pageId;
  fsRWReq->data.arrayOfPages.fileOffset = 0; // Write to file page 0
  sendSignal(NDBFS_REF, GSN_FSREADREQ, signal, 8, JBA);
}//readTableFile()

void Dbdict::readTableConf(Signal* signal,
			   FsConnectRecordPtr fsPtr)
{
  /* ---------------------------------------------------------------- */
  // Verify the data read from disk
  /* ---------------------------------------------------------------- */
  bool crashInd;
  if (fsPtr.p->fsState == FsConnectRecord::READ_TAB_FILE1) {
    jam();
    crashInd = false;
  } else {
    jam();
    crashInd = true;
  }//if

  PageRecordPtr tmpPagePtr;
  c_pageRecordArray.getPtr(tmpPagePtr, c_readTableRecord.pageId);
  Uint32 sz = c_readTableRecord.noOfPages * ZSIZE_OF_PAGES_IN_WORDS;
  Uint32 chk = computeChecksum((const Uint32*)tmpPagePtr.p, sz);
  
  ndbrequire((chk == 0) || !crashInd);
  if(chk != 0){
    jam();
    ndbrequire(fsPtr.p->fsState == FsConnectRecord::READ_TAB_FILE1);
    readTableRef(signal, fsPtr);
    return;
  }//if
  
  fsPtr.p->fsState = FsConnectRecord::CLOSE_READ_TAB_FILE;
  closeFile(signal, fsPtr.p->filePtr, fsPtr.i);
  return;
}//Dbdict::readTableConf()

void Dbdict::readTableRef(Signal* signal,
                          FsConnectRecordPtr fsPtr)
{
  fsPtr.p->fsState = FsConnectRecord::OPEN_READ_TAB_FILE2;
  openTableFile(signal, 1, fsPtr.i, c_readTableRecord.tableId, false);
  return;
}//Dbdict::readTableRef()

void Dbdict::closeReadTableConf(Signal* signal,
                                FsConnectRecordPtr fsPtr)
{
  c_fsConnectRecordPool.release(fsPtr);
  c_readTableRecord.inUse = false;
  
  execute(signal, c_readTableRecord.m_callback, 0);
  return;
}//Dbdict::closeReadTableConf()

/* ---------------------------------------------------------------- */
// Routines to handle Read/Write of Schema Files
/* ---------------------------------------------------------------- */
void
Dbdict::updateSchemaState(Signal* signal, Uint32 tableId, 
			  SchemaFile::TableEntry* te, Callback* callback){

  jam();
  PageRecordPtr pagePtr;
  c_pageRecordArray.getPtr(pagePtr, c_schemaRecord.schemaPage);

  ndbrequire(tableId < c_tableRecordPool.getSize());
  SchemaFile::TableEntry * tableEntry = getTableEntry(pagePtr.p, tableId);
  
  SchemaFile::TableState newState = 
    (SchemaFile::TableState)te->m_tableState;
  SchemaFile::TableState oldState = 
    (SchemaFile::TableState)tableEntry->m_tableState;
  
  Uint32 newVersion = te->m_tableVersion;
  Uint32 oldVersion = tableEntry->m_tableVersion;
  
  bool ok = false;
  switch(newState){
  case SchemaFile::ADD_STARTED:
    jam();
    ok = true;
    ndbrequire((oldVersion + 1) == newVersion);
    ndbrequire(oldState == SchemaFile::INIT ||
	       oldState == SchemaFile::DROP_TABLE_COMMITTED);
    break;
  case SchemaFile::TABLE_ADD_COMMITTED:
    jam();
    ok = true;
    ndbrequire(newVersion == oldVersion);
    ndbrequire(oldState == SchemaFile::ADD_STARTED);
    break;
  case SchemaFile::ALTER_TABLE_COMMITTED:
    jam();
    ok = true;
    ndbrequire((oldVersion + 1) == newVersion);
    ndbrequire(oldState == SchemaFile::TABLE_ADD_COMMITTED ||
	       oldState == SchemaFile::ALTER_TABLE_COMMITTED);
    break;
  case SchemaFile::DROP_TABLE_STARTED:
    jam();
  case SchemaFile::DROP_TABLE_COMMITTED:
    jam();
    ok = true;
    ndbrequire(false);
    break;
  case SchemaFile::INIT:
    jam();
    ok = true;
    ndbrequire((oldState == SchemaFile::ADD_STARTED));
  }//if
  ndbrequire(ok);
  
  * tableEntry = * te;
  computeChecksum((SchemaFile*)pagePtr.p);

  ndbrequire(c_writeSchemaRecord.inUse == false);
  c_writeSchemaRecord.inUse = true;
  
  c_writeSchemaRecord.pageId = c_schemaRecord.schemaPage;
  c_writeSchemaRecord.m_callback = * callback;

  startWriteSchemaFile(signal);
}

void Dbdict::startWriteSchemaFile(Signal* signal)
{
  FsConnectRecordPtr fsPtr;
  c_fsConnectRecordPool.getPtr(fsPtr, getFsConnRecord());
  fsPtr.p->fsState = FsConnectRecord::OPEN_WRITE_SCHEMA;
  openSchemaFile(signal, 0, fsPtr.i, true);
  c_writeSchemaRecord.noOfSchemaFilesHandled = 0;
}//Dbdict::startWriteSchemaFile()

void Dbdict::openSchemaFile(Signal* signal,
                            Uint32 fileNo,
                            Uint32 fsConPtr,
                            bool writeFlag) 
{
  FsOpenReq * const fsOpenReq = (FsOpenReq *)&signal->theData[0];
  fsOpenReq->userReference = reference();
  fsOpenReq->userPointer = fsConPtr;
  if (writeFlag) {
    jam();
    fsOpenReq->fileFlags = 
      FsOpenReq::OM_WRITEONLY | 
      FsOpenReq::OM_TRUNCATE | 
      FsOpenReq::OM_CREATE | 
      FsOpenReq::OM_SYNC;
  } else {
    jam();
    fsOpenReq->fileFlags = FsOpenReq::OM_READONLY;
  }//if
  fsOpenReq->fileNumber[3] = 0; // Initialise before byte changes
  FsOpenReq::setVersion(fsOpenReq->fileNumber, 1);
  FsOpenReq::setSuffix(fsOpenReq->fileNumber, FsOpenReq::S_SCHEMALOG);
  FsOpenReq::v1_setDisk(fsOpenReq->fileNumber, (fileNo + 1));
  FsOpenReq::v1_setTable(fsOpenReq->fileNumber, (Uint32)-1);
  FsOpenReq::v1_setFragment(fsOpenReq->fileNumber, (Uint32)-1);
  FsOpenReq::v1_setS(fsOpenReq->fileNumber, (Uint32)-1);
  FsOpenReq::v1_setP(fsOpenReq->fileNumber, 0);
/* ---------------------------------------------------------------- */
// File name : D1/DBDICT/P0.SchemaLog
// D1 means Disk 1 (set by fileNo + 1). Writes to both D1 and D2
// SchemaLog indicates that this is a file giving a list of current tables.
/* ---------------------------------------------------------------- */
  sendSignal(NDBFS_REF, GSN_FSOPENREQ, signal, FsOpenReq::SignalLength, JBA);
}//openSchemaFile()

void Dbdict::writeSchemaFile(Signal* signal, Uint32 filePtr, Uint32 fsConPtr) 
{
  FsReadWriteReq * const fsRWReq = (FsReadWriteReq *)&signal->theData[0];

  fsRWReq->filePointer = filePtr;
  fsRWReq->userReference = reference();
  fsRWReq->userPointer = fsConPtr;
  fsRWReq->operationFlag = 0; // Initialise before bit changes
  FsReadWriteReq::setSyncFlag(fsRWReq->operationFlag, 1);
  FsReadWriteReq::setFormatFlag(fsRWReq->operationFlag, 
                                FsReadWriteReq::fsFormatArrayOfPages);
  fsRWReq->varIndex = ZALLOCATE;
  fsRWReq->numberOfPages = 1;
// Write from memory page
  fsRWReq->data.arrayOfPages.varIndex = c_writeSchemaRecord.pageId; 
  fsRWReq->data.arrayOfPages.fileOffset = 0; // Write to file page 0
  sendSignal(NDBFS_REF, GSN_FSWRITEREQ, signal, 8, JBA);
}//writeSchemaFile()

void Dbdict::writeSchemaConf(Signal* signal,
                                FsConnectRecordPtr fsPtr)
{
  fsPtr.p->fsState = FsConnectRecord::CLOSE_WRITE_SCHEMA;
  closeFile(signal, fsPtr.p->filePtr, fsPtr.i);
  return;
}//Dbdict::writeSchemaConf()

void Dbdict::closeFile(Signal* signal, Uint32 filePtr, Uint32 fsConPtr) 
{
  FsCloseReq * const fsCloseReq = (FsCloseReq *)&signal->theData[0];
  fsCloseReq->filePointer = filePtr;
  fsCloseReq->userReference = reference();
  fsCloseReq->userPointer = fsConPtr;
  FsCloseReq::setRemoveFileFlag(fsCloseReq->fileFlag, false);
  sendSignal(NDBFS_REF, GSN_FSCLOSEREQ, signal, FsCloseReq::SignalLength, JBA);
  return;
}//closeFile()

void Dbdict::closeWriteSchemaConf(Signal* signal,
                                     FsConnectRecordPtr fsPtr)
{
  c_writeSchemaRecord.noOfSchemaFilesHandled++;
  if (c_writeSchemaRecord.noOfSchemaFilesHandled < 2) {
    jam();
    fsPtr.p->fsState = FsConnectRecord::OPEN_WRITE_SCHEMA;
    openSchemaFile(signal, 1, fsPtr.i, true);
    return;
  } 
  ndbrequire(c_writeSchemaRecord.noOfSchemaFilesHandled == 2);
  
  c_fsConnectRecordPool.release(fsPtr);

  c_writeSchemaRecord.inUse = false;
  execute(signal, c_writeSchemaRecord.m_callback, 0);
  return;
}//Dbdict::closeWriteSchemaConf()

void Dbdict::startReadSchemaFile(Signal* signal)
{
  //globalSignalLoggers.log(number(), "startReadSchemaFile");
  FsConnectRecordPtr fsPtr;
  c_fsConnectRecordPool.getPtr(fsPtr, getFsConnRecord());
  fsPtr.p->fsState = FsConnectRecord::OPEN_READ_SCHEMA1;
  openSchemaFile(signal, 0, fsPtr.i, false);
}//Dbdict::startReadSchemaFile()

void Dbdict::openReadSchemaRef(Signal* signal,
                               FsConnectRecordPtr fsPtr) 
{
  fsPtr.p->fsState = FsConnectRecord::OPEN_READ_SCHEMA2;
  openSchemaFile(signal, 1, fsPtr.i, false);
}//Dbdict::openReadSchemaRef()

void Dbdict::readSchemaFile(Signal* signal, Uint32 filePtr, Uint32 fsConPtr) 
{
  FsReadWriteReq * const fsRWReq = (FsReadWriteReq *)&signal->theData[0];

  fsRWReq->filePointer = filePtr;
  fsRWReq->userReference = reference();
  fsRWReq->userPointer = fsConPtr;
  fsRWReq->operationFlag = 0; // Initialise before bit changes
  FsReadWriteReq::setSyncFlag(fsRWReq->operationFlag, 0);
  FsReadWriteReq::setFormatFlag(fsRWReq->operationFlag, 
                                FsReadWriteReq::fsFormatArrayOfPages);
  fsRWReq->varIndex = ZALLOCATE;
  fsRWReq->numberOfPages = 1;
  fsRWReq->data.arrayOfPages.varIndex = c_readSchemaRecord.pageId; 
  fsRWReq->data.arrayOfPages.fileOffset = 0; 
  sendSignal(NDBFS_REF, GSN_FSREADREQ, signal, 8, JBA);
}//readSchemaFile()

void Dbdict::readSchemaConf(Signal* signal,
                            FsConnectRecordPtr fsPtr)
{
/* ---------------------------------------------------------------- */
// Verify the data read from disk
/* ---------------------------------------------------------------- */
  bool crashInd;
  if (fsPtr.p->fsState == FsConnectRecord::READ_SCHEMA1) {
    jam();
    crashInd = false;
  } else {
    jam();
    crashInd = true;
  }//if
  PageRecordPtr tmpPagePtr;
  c_pageRecordArray.getPtr(tmpPagePtr, c_readSchemaRecord.pageId);

  Uint32 sz = ZSIZE_OF_PAGES_IN_WORDS;
  Uint32 chk = computeChecksum((const Uint32*)tmpPagePtr.p, sz);

  ndbrequire((chk == 0) || !crashInd);

  if (chk != 0){
    jam();
    ndbrequire(fsPtr.p->fsState == FsConnectRecord::READ_SCHEMA1);
    readSchemaRef(signal, fsPtr);
    return;
  }//if
  fsPtr.p->fsState = FsConnectRecord::CLOSE_READ_SCHEMA;
  closeFile(signal, fsPtr.p->filePtr, fsPtr.i);
  return;
}//Dbdict::readSchemaConf()

void Dbdict::readSchemaRef(Signal* signal,
                           FsConnectRecordPtr fsPtr)
{
  fsPtr.p->fsState = FsConnectRecord::OPEN_READ_SCHEMA2;
  openSchemaFile(signal, 1, fsPtr.i, false);
  return;
}//Dbdict::readSchemaRef()

void Dbdict::closeReadSchemaConf(Signal* signal,
                                 FsConnectRecordPtr fsPtr)
{
  c_fsConnectRecordPool.release(fsPtr);
  ReadSchemaRecord::SchemaReadState state = c_readSchemaRecord.schemaReadState;
  c_readSchemaRecord.schemaReadState = ReadSchemaRecord::IDLE;

  switch(state) {
  case ReadSchemaRecord::INITIAL_READ :
    jam();
    sendNDB_STTORRY(signal);
    break;

  default :
    ndbrequire(false);
    break;

  }//switch
}//Dbdict::closeReadSchemaConf()

/* **************************************************************** */
/* ---------------------------------------------------------------- */
/* MODULE:          INITIALISATION MODULE ------------------------- */
/* ---------------------------------------------------------------- */
/*                                                                  */
/* This module contains initialisation of data at start/restart.    */
/* ---------------------------------------------------------------- */
/* **************************************************************** */

Dbdict::Dbdict(const class Configuration & conf):
  SimulatedBlock(DBDICT, conf),
  c_tableRecordHash(c_tableRecordPool),
  c_attributeRecordHash(c_attributeRecordPool),
  c_triggerRecordHash(c_triggerRecordPool),
  c_opCreateTable(c_opRecordPool),
  c_opDropTable(c_opRecordPool),
  c_opCreateIndex(c_opRecordPool),
  c_opDropIndex(c_opRecordPool),
  c_opAlterIndex(c_opRecordPool),
  c_opBuildIndex(c_opRecordPool),
  c_opCreateEvent(c_opRecordPool),
  c_opSubEvent(c_opRecordPool),
  c_opDropEvent(c_opRecordPool),
  c_opSignalUtil(c_opRecordPool),
  c_opCreateTrigger(c_opRecordPool),
  c_opDropTrigger(c_opRecordPool),
  c_opAlterTrigger(c_opRecordPool),
  c_opRecordSequence(0)
{
  BLOCK_CONSTRUCTOR(Dbdict);
  
  const ndb_mgm_configuration_iterator * p = conf.getOwnConfigIterator();
  ndbrequire(p != 0);

  ndb_mgm_get_int_parameter(p, CFG_DB_NO_TRIGGERS, &c_maxNoOfTriggers);
  // Transit signals
  addRecSignal(GSN_DUMP_STATE_ORD, &Dbdict::execDUMP_STATE_ORD);
  addRecSignal(GSN_GET_TABINFOREQ, &Dbdict::execGET_TABINFOREQ);
  addRecSignal(GSN_GET_TABLEID_REQ, &Dbdict::execGET_TABLEDID_REQ);
  addRecSignal(GSN_GET_TABINFO_CONF, &Dbdict::execGET_TABINFO_CONF);
  addRecSignal(GSN_CONTINUEB, &Dbdict::execCONTINUEB);

  addRecSignal(GSN_CREATE_TABLE_REQ, &Dbdict::execCREATE_TABLE_REQ);
  addRecSignal(GSN_CREATE_TAB_REQ, &Dbdict::execCREATE_TAB_REQ);
  addRecSignal(GSN_CREATE_TAB_REF, &Dbdict::execCREATE_TAB_REF);
  addRecSignal(GSN_CREATE_TAB_CONF, &Dbdict::execCREATE_TAB_CONF);
  addRecSignal(GSN_CREATE_FRAGMENTATION_REF, &Dbdict::execCREATE_FRAGMENTATION_REF);
  addRecSignal(GSN_CREATE_FRAGMENTATION_CONF, &Dbdict::execCREATE_FRAGMENTATION_CONF);
  addRecSignal(GSN_DIADDTABCONF, &Dbdict::execDIADDTABCONF);
  addRecSignal(GSN_DIADDTABREF, &Dbdict::execDIADDTABREF);
  addRecSignal(GSN_ADD_FRAGREQ, &Dbdict::execADD_FRAGREQ);
  addRecSignal(GSN_TAB_COMMITCONF, &Dbdict::execTAB_COMMITCONF);
  addRecSignal(GSN_TAB_COMMITREF, &Dbdict::execTAB_COMMITREF);
  addRecSignal(GSN_ALTER_TABLE_REQ, &Dbdict::execALTER_TABLE_REQ);
  addRecSignal(GSN_ALTER_TAB_REQ, &Dbdict::execALTER_TAB_REQ);
  addRecSignal(GSN_ALTER_TAB_REF, &Dbdict::execALTER_TAB_REF);
  addRecSignal(GSN_ALTER_TAB_CONF, &Dbdict::execALTER_TAB_CONF);

  // Index signals
  addRecSignal(GSN_CREATE_INDX_REQ, &Dbdict::execCREATE_INDX_REQ);
  addRecSignal(GSN_CREATE_INDX_CONF, &Dbdict::execCREATE_INDX_CONF);
  addRecSignal(GSN_CREATE_INDX_REF, &Dbdict::execCREATE_INDX_REF);

  addRecSignal(GSN_ALTER_INDX_REQ, &Dbdict::execALTER_INDX_REQ);
  addRecSignal(GSN_ALTER_INDX_CONF, &Dbdict::execALTER_INDX_CONF);
  addRecSignal(GSN_ALTER_INDX_REF, &Dbdict::execALTER_INDX_REF);

  addRecSignal(GSN_CREATE_TABLE_CONF, &Dbdict::execCREATE_TABLE_CONF);
  addRecSignal(GSN_CREATE_TABLE_REF, &Dbdict::execCREATE_TABLE_REF);

  addRecSignal(GSN_DROP_INDX_REQ, &Dbdict::execDROP_INDX_REQ);
  addRecSignal(GSN_DROP_INDX_CONF, &Dbdict::execDROP_INDX_CONF);
  addRecSignal(GSN_DROP_INDX_REF, &Dbdict::execDROP_INDX_REF);

  addRecSignal(GSN_DROP_TABLE_CONF, &Dbdict::execDROP_TABLE_CONF);
  addRecSignal(GSN_DROP_TABLE_REF, &Dbdict::execDROP_TABLE_REF);

  addRecSignal(GSN_BUILDINDXREQ, &Dbdict::execBUILDINDXREQ);
  addRecSignal(GSN_BUILDINDXCONF, &Dbdict::execBUILDINDXCONF);
  addRecSignal(GSN_BUILDINDXREF, &Dbdict::execBUILDINDXREF);

  // Util signals
  addRecSignal(GSN_UTIL_PREPARE_CONF, &Dbdict::execUTIL_PREPARE_CONF);
  addRecSignal(GSN_UTIL_PREPARE_REF,  &Dbdict::execUTIL_PREPARE_REF);

  addRecSignal(GSN_UTIL_EXECUTE_CONF, &Dbdict::execUTIL_EXECUTE_CONF);
  addRecSignal(GSN_UTIL_EXECUTE_REF,  &Dbdict::execUTIL_EXECUTE_REF);

  addRecSignal(GSN_UTIL_RELEASE_CONF, &Dbdict::execUTIL_RELEASE_CONF);
  addRecSignal(GSN_UTIL_RELEASE_REF,  &Dbdict::execUTIL_RELEASE_REF);

  // Event signals
  addRecSignal(GSN_CREATE_EVNT_REQ,  &Dbdict::execCREATE_EVNT_REQ);
  addRecSignal(GSN_CREATE_EVNT_CONF, &Dbdict::execCREATE_EVNT_CONF);
  addRecSignal(GSN_CREATE_EVNT_REF,  &Dbdict::execCREATE_EVNT_REF);

  addRecSignal(GSN_CREATE_SUBID_CONF, &Dbdict::execCREATE_SUBID_CONF);
  addRecSignal(GSN_CREATE_SUBID_REF,  &Dbdict::execCREATE_SUBID_REF);

  addRecSignal(GSN_SUB_CREATE_CONF, &Dbdict::execSUB_CREATE_CONF);
  addRecSignal(GSN_SUB_CREATE_REF,  &Dbdict::execSUB_CREATE_REF);

  addRecSignal(GSN_SUB_START_REQ,  &Dbdict::execSUB_START_REQ);
  addRecSignal(GSN_SUB_START_CONF,  &Dbdict::execSUB_START_CONF);
  addRecSignal(GSN_SUB_START_REF,  &Dbdict::execSUB_START_REF);

  addRecSignal(GSN_SUB_STOP_REQ,  &Dbdict::execSUB_STOP_REQ);
  addRecSignal(GSN_SUB_STOP_CONF,  &Dbdict::execSUB_STOP_CONF);
  addRecSignal(GSN_SUB_STOP_REF,  &Dbdict::execSUB_STOP_REF);

  addRecSignal(GSN_SUB_SYNC_CONF, &Dbdict::execSUB_SYNC_CONF);
  addRecSignal(GSN_SUB_SYNC_REF,  &Dbdict::execSUB_SYNC_REF);

  addRecSignal(GSN_DROP_EVNT_REQ,  &Dbdict::execDROP_EVNT_REQ);

  addRecSignal(GSN_SUB_REMOVE_REQ, &Dbdict::execSUB_REMOVE_REQ);
  addRecSignal(GSN_SUB_REMOVE_CONF, &Dbdict::execSUB_REMOVE_CONF);
  addRecSignal(GSN_SUB_REMOVE_REF,  &Dbdict::execSUB_REMOVE_REF);

  // Trigger signals
  addRecSignal(GSN_CREATE_TRIG_REQ, &Dbdict::execCREATE_TRIG_REQ);
  addRecSignal(GSN_CREATE_TRIG_CONF, &Dbdict::execCREATE_TRIG_CONF);
  addRecSignal(GSN_CREATE_TRIG_REF, &Dbdict::execCREATE_TRIG_REF);
  addRecSignal(GSN_ALTER_TRIG_REQ, &Dbdict::execALTER_TRIG_REQ);
  addRecSignal(GSN_ALTER_TRIG_CONF, &Dbdict::execALTER_TRIG_CONF);
  addRecSignal(GSN_ALTER_TRIG_REF, &Dbdict::execALTER_TRIG_REF);
  addRecSignal(GSN_DROP_TRIG_REQ, &Dbdict::execDROP_TRIG_REQ);
  addRecSignal(GSN_DROP_TRIG_CONF, &Dbdict::execDROP_TRIG_CONF);
  addRecSignal(GSN_DROP_TRIG_REF, &Dbdict::execDROP_TRIG_REF);

  // Received signals
  addRecSignal(GSN_HOT_SPAREREP, &Dbdict::execHOT_SPAREREP);
  addRecSignal(GSN_GET_SCHEMA_INFOREQ, &Dbdict::execGET_SCHEMA_INFOREQ);
  addRecSignal(GSN_SCHEMA_INFO, &Dbdict::execSCHEMA_INFO);
  addRecSignal(GSN_SCHEMA_INFOCONF, &Dbdict::execSCHEMA_INFOCONF);
  addRecSignal(GSN_DICTSTARTREQ, &Dbdict::execDICTSTARTREQ);
  addRecSignal(GSN_READ_NODESCONF, &Dbdict::execREAD_NODESCONF);
  addRecSignal(GSN_FSOPENCONF, &Dbdict::execFSOPENCONF);
  addRecSignal(GSN_FSOPENREF, &Dbdict::execFSOPENREF);
  addRecSignal(GSN_FSCLOSECONF, &Dbdict::execFSCLOSECONF);
  addRecSignal(GSN_FSCLOSEREF, &Dbdict::execFSCLOSEREF);
  addRecSignal(GSN_FSWRITECONF, &Dbdict::execFSWRITECONF);
  addRecSignal(GSN_FSWRITEREF, &Dbdict::execFSWRITEREF);
  addRecSignal(GSN_FSREADCONF, &Dbdict::execFSREADCONF);
  addRecSignal(GSN_FSREADREF, &Dbdict::execFSREADREF);
  addRecSignal(GSN_LQHFRAGCONF, &Dbdict::execLQHFRAGCONF);
  addRecSignal(GSN_LQHADDATTCONF, &Dbdict::execLQHADDATTCONF);
  addRecSignal(GSN_LQHADDATTREF, &Dbdict::execLQHADDATTREF);
  addRecSignal(GSN_LQHFRAGREF, &Dbdict::execLQHFRAGREF);
  addRecSignal(GSN_NDB_STTOR, &Dbdict::execNDB_STTOR);
  addRecSignal(GSN_READ_CONFIG_REQ, &Dbdict::execREAD_CONFIG_REQ, true);
  addRecSignal(GSN_STTOR, &Dbdict::execSTTOR);
  addRecSignal(GSN_TC_SCHVERCONF, &Dbdict::execTC_SCHVERCONF);
  addRecSignal(GSN_NODE_FAILREP, &Dbdict::execNODE_FAILREP);
  addRecSignal(GSN_INCL_NODEREQ, &Dbdict::execINCL_NODEREQ);
  addRecSignal(GSN_API_FAILREQ, &Dbdict::execAPI_FAILREQ);

  addRecSignal(GSN_WAIT_GCP_REF, &Dbdict::execWAIT_GCP_REF);
  addRecSignal(GSN_WAIT_GCP_CONF, &Dbdict::execWAIT_GCP_CONF);

  addRecSignal(GSN_LIST_TABLES_REQ, &Dbdict::execLIST_TABLES_REQ);

  addRecSignal(GSN_DROP_TABLE_REQ, &Dbdict::execDROP_TABLE_REQ);
  
  addRecSignal(GSN_PREP_DROP_TAB_REQ, &Dbdict::execPREP_DROP_TAB_REQ);
  addRecSignal(GSN_PREP_DROP_TAB_REF, &Dbdict::execPREP_DROP_TAB_REF);
  addRecSignal(GSN_PREP_DROP_TAB_CONF, &Dbdict::execPREP_DROP_TAB_CONF);
  
  addRecSignal(GSN_DROP_TAB_REQ, &Dbdict::execDROP_TAB_REQ);
  addRecSignal(GSN_DROP_TAB_REF, &Dbdict::execDROP_TAB_REF);
  addRecSignal(GSN_DROP_TAB_CONF, &Dbdict::execDROP_TAB_CONF);
}//Dbdict::Dbdict()

Dbdict::~Dbdict() 
{
}//Dbdict::~Dbdict()

BLOCK_FUNCTIONS(Dbdict)

void Dbdict::initCommonData() 
{
/* ---------------------------------------------------------------- */
// Initialise all common variables.
/* ---------------------------------------------------------------- */
  initRetrieveRecord(0, 0, 0);
  initSchemaRecord();
  initRestartRecord();
  initSendSchemaRecord();
  initReadTableRecord();
  initWriteTableRecord();
  initReadSchemaRecord();
  initWriteSchemaRecord();

  c_masterNodeId = ZNIL;
  c_numberNode = 0;
  c_noNodesFailed = 0;
  c_failureNr = 0;
  c_blockState = BS_IDLE;
  c_packTable.m_state = PackTable::PTS_IDLE;
  c_startPhase = 0;
  c_restartType = 255; //Ensure not used restartType
  c_tabinfoReceived = 0;
  c_initialStart = false;
  c_systemRestart = false;
  c_initialNodeRestart = false;
  c_nodeRestart = false;
}//Dbdict::initCommonData()

void Dbdict::initRecords() 
{
  initNodeRecords();
  initPageRecords();
  initTableRecords();
  initTriggerRecords();
}//Dbdict::initRecords()

void Dbdict::initSendSchemaRecord() 
{
  c_sendSchemaRecord.noOfWords = (Uint32)-1;
  c_sendSchemaRecord.pageId = RNIL;
  c_sendSchemaRecord.noOfWordsCurrentlySent = 0;
  c_sendSchemaRecord.noOfSignalsSentSinceDelay = 0;
  c_sendSchemaRecord.inUse = false;
  //c_sendSchemaRecord.sendSchemaState = SendSchemaRecord::IDLE;
}//initSendSchemaRecord()

void Dbdict::initReadTableRecord() 
{
  c_readTableRecord.noOfPages = (Uint32)-1;
  c_readTableRecord.pageId = RNIL;
  c_readTableRecord.tableId = ZNIL;
  c_readTableRecord.inUse = false;
}//initReadTableRecord()

void Dbdict::initWriteTableRecord() 
{
  c_writeTableRecord.noOfPages = (Uint32)-1;
  c_writeTableRecord.pageId = RNIL;
  c_writeTableRecord.noOfTableFilesHandled = 3;
  c_writeTableRecord.tableId = ZNIL;
  c_writeTableRecord.tableWriteState = WriteTableRecord::IDLE;
}//initWriteTableRecord()

void Dbdict::initReadSchemaRecord() 
{
  c_readSchemaRecord.pageId = RNIL;
  c_readSchemaRecord.schemaReadState = ReadSchemaRecord::IDLE;
}//initReadSchemaRecord()

void Dbdict::initWriteSchemaRecord() 
{
  c_writeSchemaRecord.inUse = false;
  c_writeSchemaRecord.pageId = RNIL;
  c_writeSchemaRecord.noOfSchemaFilesHandled = 3;
}//initWriteSchemaRecord()

void Dbdict::initRetrieveRecord(Signal* signal, Uint32 i, Uint32 returnCode) 
{
  c_retrieveRecord.busyState = false;
  c_retrieveRecord.blockRef = 0;
  c_retrieveRecord.m_senderData = RNIL;
  c_retrieveRecord.tableId = RNIL;
  c_retrieveRecord.currentSent = 0;
  c_retrieveRecord.retrievedNoOfPages = 0;
  c_retrieveRecord.retrievedNoOfWords = 0;
  c_retrieveRecord.m_useLongSig = false;
}//initRetrieveRecord()

void Dbdict::initSchemaRecord() 
{
  c_schemaRecord.schemaPage = RNIL;
}//Dbdict::initSchemaRecord()

void Dbdict::initRestartRecord() 
{
  c_restartRecord.gciToRestart = 0;
  c_restartRecord.activeTable = ZNIL;
}//Dbdict::initRestartRecord()

void Dbdict::initNodeRecords() 
{
  jam();
  for (unsigned i = 1; i < MAX_NODES; i++) {
    NodeRecordPtr nodePtr;
    c_nodes.getPtr(nodePtr, i);
    nodePtr.p->hotSpare = false;
    nodePtr.p->nodeState = NodeRecord::API_NODE;
  }//for
}//Dbdict::initNodeRecords()

void Dbdict::initPageRecords() 
{
  c_schemaRecord.schemaPage = ZMAX_PAGES_OF_TABLE_DEFINITION;
  c_schemaRecord.oldSchemaPage = ZMAX_PAGES_OF_TABLE_DEFINITION + 1;
  c_retrieveRecord.retrievePage =  ZMAX_PAGES_OF_TABLE_DEFINITION + 2;
  ndbrequire(ZNUMBER_OF_PAGES >= (2 * ZMAX_PAGES_OF_TABLE_DEFINITION + 2));
}//Dbdict::initPageRecords()

void Dbdict::initTableRecords() 
{
  TableRecordPtr tablePtr;
  while (1) {
    jam();
    refresh_watch_dog();
    c_tableRecordPool.seize(tablePtr);
    if (tablePtr.i == RNIL) {
      jam();
      break;
    }//if
    initialiseTableRecord(tablePtr);
  }//while
}//Dbdict::initTableRecords()

void Dbdict::initialiseTableRecord(TableRecordPtr tablePtr) 
{
  tablePtr.p->activePage = RNIL;
  tablePtr.p->filePtr[0] = RNIL;
  tablePtr.p->filePtr[1] = RNIL;
  tablePtr.p->firstAttribute = RNIL;
  tablePtr.p->firstPage = RNIL;
  tablePtr.p->lastAttribute = RNIL;
  tablePtr.p->tableId = tablePtr.i;
  tablePtr.p->tableVersion = (Uint32)-1;
  tablePtr.p->tabState = TableRecord::NOT_DEFINED;
  tablePtr.p->tabReturnState = TableRecord::TRS_IDLE;
  tablePtr.p->myConnect = RNIL;
  tablePtr.p->fragmentType = DictTabInfo::AllNodesSmallTable;
  memset(tablePtr.p->tableName, 0, sizeof(tablePtr.p->tableName));
  tablePtr.p->gciTableCreated = 0;
  tablePtr.p->noOfAttributes = ZNIL;
  tablePtr.p->noOfNullAttr = 0;
  tablePtr.p->frmLen = 0;
  memset(tablePtr.p->frmData, 0, sizeof(tablePtr.p->frmData));
  /*
    tablePtr.p->lh3PageIndexBits = 0;
    tablePtr.p->lh3DistrBits = 0;
    tablePtr.p->lh3PageBits = 6;
  */
  tablePtr.p->kValue = 6;
  tablePtr.p->localKeyLen = 1;
  tablePtr.p->maxLoadFactor = 80;
  tablePtr.p->minLoadFactor = 70;
  tablePtr.p->noOfPrimkey = 1;
  tablePtr.p->tupKeyLength = 1;
  tablePtr.p->storedTable = true;
  tablePtr.p->tableType = DictTabInfo::UserTable;
  tablePtr.p->primaryTableId = RNIL;
  // volatile elements
  tablePtr.p->indexState = TableRecord::IS_UNDEFINED;
  tablePtr.p->insertTriggerId = RNIL;
  tablePtr.p->updateTriggerId = RNIL;
  tablePtr.p->deleteTriggerId = RNIL;
  tablePtr.p->customTriggerId = RNIL;
  tablePtr.p->buildTriggerId = RNIL;
  tablePtr.p->indexLocal = 0;
}//Dbdict::initialiseTableRecord()

void Dbdict::initTriggerRecords()
{
  TriggerRecordPtr triggerPtr;
  while (1) {
    jam();
    refresh_watch_dog();
    c_triggerRecordPool.seize(triggerPtr);
    if (triggerPtr.i == RNIL) {
      jam();
      break;
    }//if
    initialiseTriggerRecord(triggerPtr);
  }//while
}

void Dbdict::initialiseTriggerRecord(TriggerRecordPtr triggerPtr)
{
  triggerPtr.p->triggerState = TriggerRecord::TS_NOT_DEFINED;
  triggerPtr.p->triggerLocal = 0;
  memset(triggerPtr.p->triggerName, 0, sizeof(triggerPtr.p->triggerName));
  triggerPtr.p->triggerId = RNIL;
  triggerPtr.p->tableId = RNIL;
  triggerPtr.p->triggerType = (TriggerType::Value)~0;
  triggerPtr.p->triggerActionTime = (TriggerActionTime::Value)~0;
  triggerPtr.p->triggerEvent = (TriggerEvent::Value)~0;
  triggerPtr.p->monitorReplicas = false;
  triggerPtr.p->monitorAllAttributes = false;
  triggerPtr.p->attributeMask.clear();
  triggerPtr.p->indexId = RNIL;
}

Uint32 Dbdict::getFsConnRecord() 
{
  FsConnectRecordPtr fsPtr;
  c_fsConnectRecordPool.seize(fsPtr);
  ndbrequire(fsPtr.i != RNIL);
  fsPtr.p->filePtr = (Uint32)-1;
  fsPtr.p->ownerPtr = RNIL;
  fsPtr.p->fsState = FsConnectRecord::IDLE;
  return fsPtr.i;
}//Dbdict::getFsConnRecord()

Uint32 Dbdict::getFreeTableRecord(Uint32 primaryTableId) 
{
  Uint32 minId = (primaryTableId == RNIL ? 0 : primaryTableId + 1);
  TableRecordPtr tablePtr;
  TableRecordPtr firstTablePtr;
  bool firstFound = false;
  Uint32 tabSize = c_tableRecordPool.getSize();
  for (tablePtr.i = minId; tablePtr.i < tabSize ; tablePtr.i++) {
    jam();
    c_tableRecordPool.getPtr(tablePtr);
    if (tablePtr.p->tabState == TableRecord::NOT_DEFINED) {
      jam();
      initialiseTableRecord(tablePtr);
      tablePtr.p->tabState = TableRecord::DEFINING;
      firstFound = true;
      firstTablePtr.i = tablePtr.i;
      firstTablePtr.p = tablePtr.p;
      break;
    }//if
  }//for
  if (!firstFound) {
    jam();
    return RNIL;
  }//if
#ifdef HAVE_TABLE_REORG
  bool secondFound = false;
  for (tablePtr.i = firstTablePtr.i + 1; tablePtr.i < tabSize ; tablePtr.i++) {
    jam();
    c_tableRecordPool.getPtr(tablePtr);
    if (tablePtr.p->tabState == TableRecord::NOT_DEFINED) {
      jam();
      initialiseTableRecord(tablePtr);
      tablePtr.p->tabState = TableRecord::REORG_TABLE_PREPARED;
      tablePtr.p->secondTable = firstTablePtr.i;
      firstTablePtr.p->secondTable = tablePtr.i;
      secondFound = true;
      break;
    }//if
  }//for
  if (!secondFound) {
    jam();
    firstTablePtr.p->tabState = TableRecord::NOT_DEFINED;
    return RNIL;
  }//if
#endif
  return firstTablePtr.i;
}//Dbdict::getFreeTableRecord()

Uint32 Dbdict::getFreeTriggerRecord()
{
  const Uint32 size = c_triggerRecordPool.getSize();
  TriggerRecordPtr triggerPtr;
  for (triggerPtr.i = 0; triggerPtr.i < size; triggerPtr.i++) {
    jam();
    c_triggerRecordPool.getPtr(triggerPtr);
    if (triggerPtr.p->triggerState == TriggerRecord::TS_NOT_DEFINED) {
      jam();
      initialiseTriggerRecord(triggerPtr);
      return triggerPtr.i;
    }
  }
  return RNIL;
}

bool
Dbdict::getNewAttributeRecord(TableRecordPtr tablePtr, 
			      AttributeRecordPtr & attrPtr) 
{
  c_attributeRecordPool.seize(attrPtr);
  if(attrPtr.i == RNIL){
    return false;
  }
  
  memset(attrPtr.p->attributeName, 0, sizeof(attrPtr.p->attributeName));
  attrPtr.p->attributeDescriptor = 0x00012255; //Default value
  attrPtr.p->attributeId = ZNIL;
  attrPtr.p->nextAttrInTable = RNIL;
  attrPtr.p->tupleKey = 0;
  memset(attrPtr.p->defaultValue, 0, sizeof(attrPtr.p->defaultValue));
  
  /* ---------------------------------------------------------------- */
  // A free attribute record has been acquired. We will now link it
  // to the table record.
  /* ---------------------------------------------------------------- */
  if (tablePtr.p->lastAttribute == RNIL) {
    jam();
    tablePtr.p->firstAttribute = attrPtr.i;
  } else {
    jam();
    AttributeRecordPtr lastAttrPtr;
    c_attributeRecordPool.getPtr(lastAttrPtr, tablePtr.p->lastAttribute);
    lastAttrPtr.p->nextAttrInTable = attrPtr.i;
  }//if
  tablePtr.p->lastAttribute = attrPtr.i;
  return true;
}//Dbdict::getNewAttributeRecord()

/* **************************************************************** */
/* ---------------------------------------------------------------- */
/* MODULE:          START/RESTART HANDLING ------------------------ */
/* ---------------------------------------------------------------- */
/*                                                                  */
/* This module contains the code that is common for all             */
/* start/restart types.                                             */
/* ---------------------------------------------------------------- */
/* **************************************************************** */

/* ---------------------------------------------------------------- */
// This is sent as the first signal during start/restart.
/* ---------------------------------------------------------------- */
void Dbdict::execSTTOR(Signal* signal) 
{
  jamEntry();
  c_startPhase = signal->theData[1];
  switch (c_startPhase) {
  case 1:
    break;
  case 3:
    c_restartType = signal->theData[7];         /* valid if 3 */
    ndbrequire(c_restartType == NodeState::ST_INITIAL_START ||
               c_restartType == NodeState::ST_SYSTEM_RESTART ||
               c_restartType == NodeState::ST_INITIAL_NODE_RESTART ||
               c_restartType == NodeState::ST_NODE_RESTART);
    break;
  }
  sendSTTORRY(signal);
}//execSTTOR()

void Dbdict::sendSTTORRY(Signal* signal)
{
  signal->theData[0] = 0;       /* garbage SIGNAL KEY */
  signal->theData[1] = 0;       /* garbage SIGNAL VERSION NUMBER  */
  signal->theData[2] = 0;       /* garbage */
  signal->theData[3] = 1;       /* first wanted start phase */
  signal->theData[4] = 3;       /* get type of start */
  signal->theData[5] = ZNOMOREPHASES;
  sendSignal(NDBCNTR_REF, GSN_STTORRY, signal, 6, JBB);
}

/* ---------------------------------------------------------------- */
// We receive information about sizes of records.
/* ---------------------------------------------------------------- */
void Dbdict::execREAD_CONFIG_REQ(Signal* signal) 
{
  const ReadConfigReq * req = (ReadConfigReq*)signal->getDataPtr();
  Uint32 ref = req->senderRef;
  Uint32 senderData = req->senderData;
  ndbrequire(req->noOfParameters == 0);

  jamEntry();
 
  const ndb_mgm_configuration_iterator * p = 
    theConfiguration.getOwnConfigIterator();
  ndbrequire(p != 0);
  
  Uint32 attributesize, tablerecSize;
  ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DICT_ATTRIBUTE,&attributesize));
  ndbrequire(!ndb_mgm_get_int_parameter(p, CFG_DICT_TABLE, &tablerecSize));

  c_attributeRecordPool.setSize(attributesize);
  c_attributeRecordHash.setSize(64);
  c_fsConnectRecordPool.setSize(ZFS_CONNECT_SIZE);
  c_nodes.setSize(MAX_NODES);
  c_pageRecordArray.setSize(ZNUMBER_OF_PAGES);
  c_tableRecordPool.setSize(tablerecSize);
  c_tableRecordHash.setSize(tablerecSize);
  c_triggerRecordPool.setSize(c_maxNoOfTriggers);
  c_triggerRecordHash.setSize(c_maxNoOfTriggers);
  c_opRecordPool.setSize(256);   // XXX need config params
  c_opCreateTable.setSize(8);
  c_opDropTable.setSize(8);
  c_opCreateIndex.setSize(8);
  c_opCreateEvent.setSize(8);
  c_opSubEvent.setSize(8);
  c_opDropEvent.setSize(8);
  c_opSignalUtil.setSize(8);
  c_opDropIndex.setSize(8);
  c_opAlterIndex.setSize(8);
  c_opBuildIndex.setSize(8);
  c_opCreateTrigger.setSize(8);
  c_opDropTrigger.setSize(8);
  c_opAlterTrigger.setSize(8);

  // Initialize BAT for interface to file system
  PageRecordPtr pageRecPtr;
  c_pageRecordArray.getPtr(pageRecPtr, 0);
  NewVARIABLE* bat = allocateBat(2);
  bat[1].WA = &pageRecPtr.p->word[0];
  bat[1].nrr = ZNUMBER_OF_PAGES;
  bat[1].ClusterSize = ZSIZE_OF_PAGES_IN_WORDS * 4;
  bat[1].bits.q = ZLOG_SIZE_OF_PAGES_IN_WORDS; // 2**13 = 8192 elements
  bat[1].bits.v = 5;  // 32 bits per element

  initCommonData();
  initRecords();

  ReadConfigConf * conf = (ReadConfigConf*)signal->getDataPtrSend();
  conf->senderRef = reference();
  conf->senderData = senderData;
  sendSignal(ref, GSN_READ_CONFIG_CONF, signal, 
	     ReadConfigConf::SignalLength, JBB);
}//execSIZEALT_REP()

/* ---------------------------------------------------------------- */
// Start phase signals sent by CNTR. We reply with NDB_STTORRY when
// we completed this phase.
/* ---------------------------------------------------------------- */
void Dbdict::execNDB_STTOR(Signal* signal) 
{
  jamEntry();
  c_startPhase = signal->theData[2];
  const Uint32 restartType = signal->theData[3];
  if (restartType == NodeState::ST_INITIAL_START) {
    jam();
    c_initialStart = true;
  } else if (restartType == NodeState::ST_SYSTEM_RESTART) {
    jam();
    c_systemRestart = true;
  } else if (restartType == NodeState::ST_INITIAL_NODE_RESTART) {
    jam();
    c_initialNodeRestart = true;
  } else if (restartType == NodeState::ST_NODE_RESTART) {
    jam();
    c_nodeRestart = true;
  } else {
    ndbrequire(false);
  }//if
  switch (c_startPhase) {
  case 1:
    jam();
    initSchemaFile(signal);
    break;
  case 3:
    jam();
    signal->theData[0] = reference();
    sendSignal(NDBCNTR_REF, GSN_READ_NODESREQ, signal, 1, JBB);
    break;
  case 6:
    jam();
    c_initialStart = false;
    c_systemRestart = false;
    c_initialNodeRestart = false;
    c_nodeRestart = false;
    sendNDB_STTORRY(signal);
    break;
  case 7:
    // uses c_restartType
    if(restartType == NodeState::ST_SYSTEM_RESTART &&
       c_masterNodeId == getOwnNodeId()){
      rebuildIndexes(signal, 0);
      return;
    }
    sendNDB_STTORRY(signal);
    break;
  default:
    jam();
    sendNDB_STTORRY(signal);
    break;
  }//switch
}//execNDB_STTOR()

void Dbdict::sendNDB_STTORRY(Signal* signal) 
{
  signal->theData[0] = reference();
  sendSignal(NDBCNTR_REF, GSN_NDB_STTORRY, signal, 1, JBB);
  return;
}//sendNDB_STTORRY()

/* ---------------------------------------------------------------- */
// We receive the information about which nodes that are up and down.
/* ---------------------------------------------------------------- */
void Dbdict::execREAD_NODESCONF(Signal* signal) 
{
  jamEntry();

  ReadNodesConf * const readNodes = (ReadNodesConf *)&signal->theData[0];
  c_numberNode   = readNodes->noOfNodes;
  c_masterNodeId = readNodes->masterNodeId;

  c_noNodesFailed = 0;
  c_aliveNodes.clear();
  for (unsigned i = 1; i < MAX_NDB_NODES; i++) {
    jam();
    NodeRecordPtr nodePtr;
    c_nodes.getPtr(nodePtr, i);

    if (NodeBitmask::get(readNodes->allNodes, i)) {
      jam();
      nodePtr.p->nodeState = NodeRecord::NDB_NODE_ALIVE;
      if (NodeBitmask::get(readNodes->inactiveNodes, i)) {
	jam();
	/**-------------------------------------------------------------------
	 *
	 * THIS NODE IS DEFINED IN THE CLUSTER BUT IS NOT ALIVE CURRENTLY.
	 * WE ADD THE NODE TO THE SET OF FAILED NODES AND ALSO SET THE
	 * BLOCKSTATE TO BUSY TO AVOID ADDING TABLES WHILE NOT ALL NODES ARE
	 * ALIVE.
	 *------------------------------------------------------------------*/
        nodePtr.p->nodeState = NodeRecord::NDB_NODE_DEAD;
	c_noNodesFailed++;
      } else {
	c_aliveNodes.set(i);
      }
    }//if
  }//for
  sendNDB_STTORRY(signal);
}//execREAD_NODESCONF()

/* ---------------------------------------------------------------- */
// HOT_SPAREREP informs DBDICT about which nodes that have become
// hot spare nodes.
/* ---------------------------------------------------------------- */
void Dbdict::execHOT_SPAREREP(Signal* signal) 
{
  Uint32 hotSpareNodes = 0;
  jamEntry();
  HotSpareRep * const hotSpare = (HotSpareRep*)&signal->theData[0];
  for (unsigned i = 1; i < MAX_NDB_NODES; i++) {
    if (NodeBitmask::get(hotSpare->theHotSpareNodes, i)) {
      NodeRecordPtr nodePtr;
      c_nodes.getPtr(nodePtr, i);
      nodePtr.p->hotSpare = true;
      hotSpareNodes++;
    }//if
  }//for
  ndbrequire(hotSpareNodes == hotSpare->noHotSpareNodes);
  c_noHotSpareNodes = hotSpareNodes;
  return;
}//execHOT_SPAREREP()

void Dbdict::initSchemaFile(Signal* signal) 
{
  PageRecordPtr pagePtr;
  c_pageRecordArray.getPtr(pagePtr, c_schemaRecord.schemaPage);
  SchemaFile * schemaFile = (SchemaFile *)pagePtr.p;
  initSchemaFile(schemaFile, 4 * ZSIZE_OF_PAGES_IN_WORDS);
  
  if (c_initialStart || c_initialNodeRestart) {    
    jam();
    ndbrequire(c_writeSchemaRecord.inUse == false);
    c_writeSchemaRecord.inUse = true;
    c_writeSchemaRecord.pageId = c_schemaRecord.schemaPage;

    c_writeSchemaRecord.m_callback.m_callbackFunction = 
      safe_cast(&Dbdict::initSchemaFile_conf);
    
    startWriteSchemaFile(signal);
  } else if (c_systemRestart || c_nodeRestart) {
    jam();
    ndbrequire(c_readSchemaRecord.schemaReadState == ReadSchemaRecord::IDLE);
    c_readSchemaRecord.pageId = c_schemaRecord.oldSchemaPage;
    c_readSchemaRecord.schemaReadState = ReadSchemaRecord::INITIAL_READ;
    startReadSchemaFile(signal);
  } else {
    ndbrequire(false);
  }//if
}//Dbdict::initSchemaFile()

void
Dbdict::initSchemaFile_conf(Signal* signal, Uint32 callbackData, Uint32 rv){
  jam();
  sendNDB_STTORRY(signal);
}

void
Dbdict::activateIndexes(Signal* signal, Uint32 i)
{
  AlterIndxReq* req = (AlterIndxReq*)signal->getDataPtrSend();
  TableRecordPtr tablePtr;
  for (; i < c_tableRecordPool.getSize(); i++) {
    tablePtr.i = i;
    c_tableRecordPool.getPtr(tablePtr);
    if (tablePtr.p->tabState != TableRecord::DEFINED)
      continue;
    if (! tablePtr.p->isIndex())
      continue;
    jam();
    req->setUserRef(reference());
    req->setConnectionPtr(i);
    req->setTableId(tablePtr.p->primaryTableId);
    req->setIndexId(tablePtr.i);
    req->setIndexVersion(tablePtr.p->tableVersion);
    req->setOnline(true);
    if (c_restartType == NodeState::ST_SYSTEM_RESTART) {
      if (c_masterNodeId != getOwnNodeId())
        continue;
      // from file index state is not defined currently
      req->setRequestType(AlterIndxReq::RT_SYSTEMRESTART);
      req->addRequestFlag((Uint32)RequestFlag::RF_NOBUILD);
    }
    else if (
        c_restartType == NodeState::ST_NODE_RESTART ||
        c_restartType == NodeState::ST_INITIAL_NODE_RESTART) {
      // from master index must be online
      if (tablePtr.p->indexState != TableRecord::IS_ONLINE)
        continue;
      req->setRequestType(AlterIndxReq::RT_NODERESTART);
      // activate locally, rebuild not needed
      req->addRequestFlag((Uint32)RequestFlag::RF_LOCAL);
      req->addRequestFlag((Uint32)RequestFlag::RF_NOBUILD);
    } else {
      ndbrequire(false);
    }
    sendSignal(reference(), GSN_ALTER_INDX_REQ,
      signal, AlterIndxReq::SignalLength, JBB);
    return;
  }
  signal->theData[0] = reference();
  sendSignal(c_restartRecord.returnBlockRef, GSN_DICTSTARTCONF,
	     signal, 1, JBB);
}

void
Dbdict::rebuildIndexes(Signal* signal, Uint32 i){
  BuildIndxReq* const req = (BuildIndxReq*)signal->getDataPtrSend();
  
  TableRecordPtr indexPtr;
  for (; i < c_tableRecordPool.getSize(); i++) {
    indexPtr.i = i;
    c_tableRecordPool.getPtr(indexPtr);
    if (indexPtr.p->tabState != TableRecord::DEFINED)
      continue;
    if (! indexPtr.p->isIndex())
      continue;

    jam();

    req->setUserRef(reference());
    req->setConnectionPtr(i);
    req->setRequestType(BuildIndxReq::RT_SYSTEMRESTART);
    req->setBuildId(0);   // not used
    req->setBuildKey(0);  // not used
    req->setIndexType(indexPtr.p->tableType);
    req->setIndexId(indexPtr.i);
    req->setTableId(indexPtr.p->primaryTableId);
    req->setParallelism(16);

    // from file index state is not defined currently
    if (indexPtr.p->storedTable) {
      // rebuild not needed
      req->addRequestFlag((Uint32)RequestFlag::RF_NOBUILD);
    }
    
    // send
    sendSignal(reference(), GSN_BUILDINDXREQ,
	       signal, BuildIndxReq::SignalLength, JBB);
    return;
  }
  sendNDB_STTORRY(signal);
}


/* **************************************************************** */
/* ---------------------------------------------------------------- */
/* MODULE:          SYSTEM RESTART MODULE ------------------------- */
/* ---------------------------------------------------------------- */
/*                                                                  */
/* This module contains code specific for system restart            */
/* ---------------------------------------------------------------- */
/* **************************************************************** */

/* ---------------------------------------------------------------- */
// DIH asks DICT to read in table data from disk during system
// restart. DIH also asks DICT to send information about which
// tables that should be started as part of this system restart.
// DICT will also activate the tables in TC as part of this process.
/* ---------------------------------------------------------------- */
void Dbdict::execDICTSTARTREQ(Signal* signal) 
{
  jamEntry();
  c_restartRecord.gciToRestart = signal->theData[0];
  c_restartRecord.returnBlockRef = signal->theData[1];
  if (c_nodeRestart || c_initialNodeRestart) {
    jam();   

    CRASH_INSERTION(6000);

    BlockReference dictRef = calcDictBlockRef(c_masterNodeId);
    signal->theData[0] = getOwnNodeId();
    sendSignal(dictRef, GSN_GET_SCHEMA_INFOREQ, signal, 1, JBB);
    return;
  }
  ndbrequire(c_systemRestart);
  ndbrequire(c_masterNodeId == getOwnNodeId());

  c_schemaRecord.m_callback.m_callbackData = 0;
  c_schemaRecord.m_callback.m_callbackFunction = 
    safe_cast(&Dbdict::masterRestart_checkSchemaStatusComplete);

  c_restartRecord.activeTable = 0;
  c_schemaRecord.schemaPage = c_schemaRecord.oldSchemaPage;
  checkSchemaStatus(signal);
}//execDICTSTARTREQ()

void
Dbdict::masterRestart_checkSchemaStatusComplete(Signal* signal,
						Uint32 callbackData,
						Uint32 returnCode){

  c_schemaRecord.schemaPage = ZMAX_PAGES_OF_TABLE_DEFINITION;

  LinearSectionPtr ptr[3];

  PageRecordPtr pagePtr;
  c_pageRecordArray.getPtr(pagePtr, c_schemaRecord.oldSchemaPage);

  ptr[0].p = &pagePtr.p->word[0];
  ptr[0].sz = ZSIZE_OF_PAGES_IN_WORDS;

  c_sendSchemaRecord.m_SCHEMAINFO_Counter = c_aliveNodes;
  NodeReceiverGroup rg(DBDICT, c_aliveNodes);

  rg.m_nodes.clear(getOwnNodeId());
  Callback c = { 0, 0 };
  sendFragmentedSignal(rg,
		       GSN_SCHEMA_INFO,
		       signal, 
		       1, //SchemaInfo::SignalLength,
		       JBB,
		       ptr,
		       1,
		       c);

  PageRecordPtr newPagePtr;
  c_pageRecordArray.getPtr(newPagePtr, c_schemaRecord.schemaPage);
  memcpy(&newPagePtr.p->word[0], &pagePtr.p->word[0], 
	 4 *  ZSIZE_OF_PAGES_IN_WORDS);

  signal->theData[0] = getOwnNodeId();
  sendSignal(reference(), GSN_SCHEMA_INFOCONF, signal, 1, JBB);
}

void 
Dbdict::execGET_SCHEMA_INFOREQ(Signal* signal){

  const Uint32 ref = signal->getSendersBlockRef();
  //const Uint32 senderData = signal->theData[0];
  
  ndbrequire(c_sendSchemaRecord.inUse == false);
  c_sendSchemaRecord.inUse = true;

  LinearSectionPtr ptr[3];
  
  PageRecordPtr pagePtr;
  c_pageRecordArray.getPtr(pagePtr, c_schemaRecord.schemaPage);
  
  ptr[0].p = &pagePtr.p->word[0];
  ptr[0].sz = ZSIZE_OF_PAGES_IN_WORDS;

  Callback c = { safe_cast(&Dbdict::sendSchemaComplete), 0 };
  sendFragmentedSignal(ref,
		       GSN_SCHEMA_INFO,
		       signal, 
		       1, //GetSchemaInfoConf::SignalLength,
		       JBB,
		       ptr,
		       1,
		       c);
}//Dbdict::execGET_SCHEMA_INFOREQ()

void
Dbdict::sendSchemaComplete(Signal * signal, 
			   Uint32 callbackData,
			   Uint32 returnCode){
  ndbrequire(c_sendSchemaRecord.inUse == true);
  c_sendSchemaRecord.inUse = false;

}


/* ---------------------------------------------------------------- */
// We receive the schema info from master as part of all restarts
// except the initial start where no tables exists.
/* ---------------------------------------------------------------- */
void Dbdict::execSCHEMA_INFO(Signal* signal) 
{
  jamEntry();
  if(!assembleFragments(signal)){
    jam();
    return;
  }

  if(getNodeState().getNodeRestartInProgress()){
    CRASH_INSERTION(6001);
  }

  SegmentedSectionPtr schemaDataPtr;
  signal->getSection(schemaDataPtr, 0);

  PageRecordPtr pagePtr;
  c_pageRecordArray.getPtr(pagePtr, c_schemaRecord.schemaPage);
  copy(&pagePtr.p->word[0], schemaDataPtr);
  releaseSections(signal);
    
  validateChecksum((SchemaFile*)pagePtr.p);

  ndbrequire(signal->getSendersBlockRef() != reference());
    
  /* ---------------------------------------------------------------- */
  // Synchronise our view on data with other nodes in the cluster.
  // This is an important part of restart handling where we will handle
  // cases where the table have been added but only partially, where
  // tables have been deleted but not completed the deletion yet and
  // other scenarios needing synchronisation.
  /* ---------------------------------------------------------------- */
  c_schemaRecord.m_callback.m_callbackData = 0;
  c_schemaRecord.m_callback.m_callbackFunction = 
    safe_cast(&Dbdict::restart_checkSchemaStatusComplete);
  c_restartRecord.activeTable = 0;
  checkSchemaStatus(signal);
}//execSCHEMA_INFO()

void
Dbdict::restart_checkSchemaStatusComplete(Signal * signal, 
					  Uint32 callbackData,
					  Uint32 returnCode){

  ndbrequire(c_writeSchemaRecord.inUse == false);
  c_writeSchemaRecord.inUse = true;
  c_writeSchemaRecord.pageId = c_schemaRecord.schemaPage;
  c_writeSchemaRecord.m_callback.m_callbackData = 0;
  c_writeSchemaRecord.m_callback.m_callbackFunction = 
    safe_cast(&Dbdict::restart_writeSchemaConf);
  
  startWriteSchemaFile(signal);
}

void
Dbdict::restart_writeSchemaConf(Signal * signal, 
				Uint32 callbackData,
				Uint32 returnCode){

  if(c_systemRestart){
    jam();
    signal->theData[0] = getOwnNodeId();
    sendSignal(calcDictBlockRef(c_masterNodeId), GSN_SCHEMA_INFOCONF,
	       signal, 1, JBB);
    return;
  }
  
  ndbrequire(c_nodeRestart || c_initialNodeRestart);
  c_blockState = BS_IDLE;
  activateIndexes(signal, 0);
  return;
}

void Dbdict::execSCHEMA_INFOCONF(Signal* signal) 
{
  jamEntry();
  ndbrequire(signal->getNoOfSections() == 0);

/* ---------------------------------------------------------------- */
// This signal is received in the master as part of system restart
// from all nodes (including the master) after they have synchronised
// their data with the master node's schema information.
/* ---------------------------------------------------------------- */
  const Uint32 nodeId = signal->theData[0];
  c_sendSchemaRecord.m_SCHEMAINFO_Counter.clearWaitingFor(nodeId);

  if (!c_sendSchemaRecord.m_SCHEMAINFO_Counter.done()){
    jam();
    return;
  }//if
  activateIndexes(signal, 0);
}//execSCHEMA_INFOCONF()

void Dbdict::checkSchemaStatus(Signal* signal) 
{
  PageRecordPtr pagePtr;
  c_pageRecordArray.getPtr(pagePtr, c_schemaRecord.schemaPage);

  PageRecordPtr oldPagePtr;
  c_pageRecordArray.getPtr(oldPagePtr, c_schemaRecord.oldSchemaPage);

  for (; c_restartRecord.activeTable < MAX_TABLES; 
       c_restartRecord.activeTable++) {
    jam();

    Uint32 tableId = c_restartRecord.activeTable;
    SchemaFile::TableEntry *newEntry = getTableEntry(pagePtr.p, tableId);
    SchemaFile::TableEntry *oldEntry = getTableEntry(oldPagePtr.p, tableId, 
						     true);
    SchemaFile::TableState schemaState = 
      (SchemaFile::TableState)newEntry->m_tableState;
    SchemaFile::TableState oldSchemaState = 
      (SchemaFile::TableState)oldEntry->m_tableState;

    if (c_restartRecord.activeTable >= c_tableRecordPool.getSize()) {
      jam();
      ndbrequire(schemaState == SchemaFile::INIT);
      ndbrequire(oldSchemaState == SchemaFile::INIT);
      continue;
    }//if

    switch(schemaState){
    case SchemaFile::INIT:{
      jam();
      bool ok = false;
      switch(oldSchemaState) {
      case SchemaFile::INIT:
	jam();
      case SchemaFile::DROP_TABLE_COMMITTED:
	jam();
	ok = true;
        jam();
	break;

      case SchemaFile::ADD_STARTED:
	jam();
      case SchemaFile::TABLE_ADD_COMMITTED:
	jam();
      case SchemaFile::DROP_TABLE_STARTED:
	jam();
      case SchemaFile::ALTER_TABLE_COMMITTED:
	jam();
	ok = true;
        jam();
	newEntry->m_tableState = SchemaFile::INIT;
	restartDropTab(signal, tableId);
	return;
      }//switch
      ndbrequire(ok);
      break;
    }
    case SchemaFile::ADD_STARTED:{
      jam();
      bool ok = false;
      switch(oldSchemaState) {
      case SchemaFile::INIT:
	jam();
      case SchemaFile::DROP_TABLE_COMMITTED:
	jam();
	ok = true;
	break;
      case SchemaFile::ADD_STARTED: 
	jam();
      case SchemaFile::DROP_TABLE_STARTED:
	jam();
      case SchemaFile::TABLE_ADD_COMMITTED:
	jam();
      case SchemaFile::ALTER_TABLE_COMMITTED:
	jam();
	ok = true;
	//------------------------------------------------------------------
	// Add Table was started but not completed. Will be dropped in all
	// nodes. Update schema information (restore table version).
	//------------------------------------------------------------------
	newEntry->m_tableState = SchemaFile::INIT;
	restartDropTab(signal, tableId);
	return;
      }
      ndbrequire(ok);
      break;
    }
    case SchemaFile::TABLE_ADD_COMMITTED:{
      jam();
      bool ok = false;
      switch(oldSchemaState) {
      case SchemaFile::INIT:
	jam();
      case SchemaFile::ADD_STARTED:
	jam();
      case SchemaFile::DROP_TABLE_STARTED:
	jam();
      case SchemaFile::DROP_TABLE_COMMITTED:
	jam();
	ok = true;
	//------------------------------------------------------------------
	// Table was added in the master node but not in our node. We can
	// retrieve the table definition from the master.
	//------------------------------------------------------------------
	restartCreateTab(signal, tableId, oldEntry, false);
        return;
        break;
      case SchemaFile::TABLE_ADD_COMMITTED:
	jam();
      case SchemaFile::ALTER_TABLE_COMMITTED:
        jam();
	ok = true;
	//------------------------------------------------------------------
	// Table was added in both our node and the master node. We can
	// retrieve the table definition from our own disk.
	//------------------------------------------------------------------
	if(* newEntry == * oldEntry){
          jam();
	  
          TableRecordPtr tablePtr;
          c_tableRecordPool.getPtr(tablePtr, tableId);
          tablePtr.p->tableVersion = oldEntry->m_tableVersion;
          tablePtr.p->tableType = (DictTabInfo::TableType)oldEntry->m_tableType;
	  
          // On NR get index from master because index state is not on file
          const bool file = c_systemRestart || tablePtr.p->isTable();
          restartCreateTab(signal, tableId, oldEntry, file);

          return;
        } else {
	  //------------------------------------------------------------------
	  // Must be a new version of the table if anything differs. Both table
	  // version and global checkpoint must be different.
	  // This should not happen for the master node. This can happen after
	  // drop table followed by add table or after change table.
	  // Not supported in this version.
	  //------------------------------------------------------------------
          ndbrequire(c_masterNodeId != getOwnNodeId());
	  ndbrequire(newEntry->m_tableVersion != oldEntry->m_tableVersion);
          jam();
	  
	  restartCreateTab(signal, tableId, oldEntry, false);
          return;
        }//if
	ndbrequire(ok);
	break;
      }
    }
    case SchemaFile::DROP_TABLE_STARTED:
      jam();
    case SchemaFile::DROP_TABLE_COMMITTED:{
      jam();
      bool ok = false;
      switch(oldSchemaState){
      case SchemaFile::INIT:
	jam();
      case SchemaFile::DROP_TABLE_COMMITTED:
	jam();
	ok = true;
	break;
      case SchemaFile::ADD_STARTED:
	jam();
      case SchemaFile::TABLE_ADD_COMMITTED:
	jam();
      case SchemaFile::DROP_TABLE_STARTED:
	jam();
      case SchemaFile::ALTER_TABLE_COMMITTED:
	jam();
	newEntry->m_tableState = SchemaFile::INIT;
	restartDropTab(signal, tableId);
	return;
      }
      ndbrequire(ok);
      break;
    }
    case SchemaFile::ALTER_TABLE_COMMITTED: {
      jam();
      bool ok = false;
      switch(oldSchemaState) {
      case SchemaFile::INIT:
	jam();
      case SchemaFile::ADD_STARTED:
	jam();
      case SchemaFile::DROP_TABLE_STARTED:
	jam();
      case SchemaFile::DROP_TABLE_COMMITTED:
	jam();
      case SchemaFile::TABLE_ADD_COMMITTED:
        jam();
	ok = true;
	//------------------------------------------------------------------
	// Table was altered in the master node but not in our node. We can
	// retrieve the altered table definition from the master.
	//------------------------------------------------------------------
	restartCreateTab(signal, tableId, oldEntry, false);
        return;
        break;
      case SchemaFile::ALTER_TABLE_COMMITTED:
        jam();
	ok = true;
	
	//------------------------------------------------------------------
	// Table was altered in both our node and the master node. We can
	// retrieve the table definition from our own disk.
	//------------------------------------------------------------------
	TableRecordPtr tablePtr;
	c_tableRecordPool.getPtr(tablePtr, tableId);
	tablePtr.p->tableVersion = oldEntry->m_tableVersion;
	tablePtr.p->tableType = (DictTabInfo::TableType)oldEntry->m_tableType;
	
	// On NR get index from master because index state is not on file
	const bool file = c_systemRestart || tablePtr.p->isTable();
	restartCreateTab(signal, tableId, oldEntry, file);

	return;
      }
      ndbrequire(ok);
      break;
    }
    }
  }
  
  execute(signal, c_schemaRecord.m_callback, 0);
}//checkSchemaStatus()

void
Dbdict::restartCreateTab(Signal* signal, Uint32 tableId, 
		      const SchemaFile::TableEntry * te, bool file){
  jam();
  
  CreateTableRecordPtr createTabPtr;  
  c_opCreateTable.seize(createTabPtr);
  ndbrequire(!createTabPtr.isNull());

  createTabPtr.p->key = ++c_opRecordSequence;
  c_opCreateTable.add(createTabPtr);
  
  createTabPtr.p->m_errorCode = 0;
  createTabPtr.p->m_tablePtrI = tableId;
  createTabPtr.p->m_coordinatorRef = reference();
  createTabPtr.p->m_senderRef = 0;
  createTabPtr.p->m_senderData = RNIL;
  createTabPtr.p->m_tabInfoPtrI = RNIL;
  createTabPtr.p->m_dihAddFragPtr = RNIL;

  if(file && !ERROR_INSERTED(6002)){
    jam();
    
    c_readTableRecord.noOfPages = te->m_noOfPages;
    c_readTableRecord.pageId = 0;
    c_readTableRecord.m_callback.m_callbackData = createTabPtr.p->key;
    c_readTableRecord.m_callback.m_callbackFunction = 
      safe_cast(&Dbdict::restartCreateTab_readTableConf);
    
    startReadTableFile(signal, tableId);
    return;
  } else {
    
    ndbrequire(c_masterNodeId != getOwnNodeId());
    
    /**
     * Get from master
     */
    GetTabInfoReq * const req = (GetTabInfoReq *)&signal->theData[0];
    req->senderRef = reference();
    req->senderData = createTabPtr.p->key;
    req->requestType = GetTabInfoReq::RequestById |
      GetTabInfoReq::LongSignalConf;
    req->tableId = tableId;
    sendSignal(calcDictBlockRef(c_masterNodeId), GSN_GET_TABINFOREQ, signal,
	       GetTabInfoReq::SignalLength, JBB);

    if(ERROR_INSERTED(6002)){
      NdbSleep_MilliSleep(10);
      CRASH_INSERTION(6002);
    }
  }
}

void
Dbdict::restartCreateTab_readTableConf(Signal* signal, 
				       Uint32 callbackData,
				       Uint32 returnCode){
  jam();
  
  PageRecordPtr pageRecPtr;
  c_pageRecordArray.getPtr(pageRecPtr, c_readTableRecord.pageId);

  ParseDictTabInfoRecord parseRecord;
  parseRecord.requestType = DictTabInfo::GetTabInfoConf;
  parseRecord.errorCode = 0;
  
  Uint32 sz = c_readTableRecord.noOfPages * ZSIZE_OF_PAGES_IN_WORDS; 
  SimplePropertiesLinearReader r(&pageRecPtr.p->word[0], sz);
  handleTabInfoInit(r, &parseRecord);
  ndbrequire(parseRecord.errorCode == 0);
  
  /* ---------------------------------------------------------------- */
  // We have read the table description from disk as part of system restart.
  // We will also write it back again to ensure that both copies are ok.
  /* ---------------------------------------------------------------- */
  ndbrequire(c_writeTableRecord.tableWriteState == WriteTableRecord::IDLE);
  c_writeTableRecord.noOfPages = c_readTableRecord.noOfPages;
  c_writeTableRecord.pageId = c_readTableRecord.pageId;
  c_writeTableRecord.tableWriteState = WriteTableRecord::TWR_CALLBACK;
  c_writeTableRecord.m_callback.m_callbackData = callbackData;
  c_writeTableRecord.m_callback.m_callbackFunction = 
    safe_cast(&Dbdict::restartCreateTab_writeTableConf);
  startWriteTableFile(signal, c_readTableRecord.tableId);
}

void
Dbdict::execGET_TABINFO_CONF(Signal* signal){
  jamEntry();

  if(!assembleFragments(signal)){
    jam();
    return;
  }
  
  GetTabInfoConf * const conf = (GetTabInfoConf*)signal->getDataPtr();

  const Uint32 tableId = conf->tableId;
  const Uint32 senderData = conf->senderData;
  
  SegmentedSectionPtr tabInfoPtr;
  signal->getSection(tabInfoPtr, GetTabInfoConf::DICT_TAB_INFO);

  CreateTableRecordPtr createTabPtr;  
  ndbrequire(c_opCreateTable.find(createTabPtr, senderData));
  ndbrequire(!createTabPtr.isNull());
  ndbrequire(createTabPtr.p->m_tablePtrI == tableId);

  /**
   * Put data into table record
   */
  ParseDictTabInfoRecord parseRecord;
  parseRecord.requestType = DictTabInfo::GetTabInfoConf;
  parseRecord.errorCode = 0;
  
  SimplePropertiesSectionReader r(tabInfoPtr, getSectionSegmentPool());
  handleTabInfoInit(r, &parseRecord);
  ndbrequire(parseRecord.errorCode == 0);
  
  Callback callback;
  callback.m_callbackData = createTabPtr.p->key;
  callback.m_callbackFunction = 
    safe_cast(&Dbdict::restartCreateTab_writeTableConf);
  
  signal->header.m_noOfSections = 0;
  writeTableFile(signal, createTabPtr.p->m_tablePtrI, tabInfoPtr, &callback);
  signal->setSection(tabInfoPtr, 0);
  releaseSections(signal);
}

void
Dbdict::restartCreateTab_writeTableConf(Signal* signal, 
					Uint32 callbackData,
					Uint32 returnCode){
  jam();

  CreateTableRecordPtr createTabPtr;  
  ndbrequire(c_opCreateTable.find(createTabPtr, callbackData));

  Callback callback;
  callback.m_callbackData = callbackData;
  callback.m_callbackFunction = 
    safe_cast(&Dbdict::restartCreateTab_dihComplete);
  
  SegmentedSectionPtr fragDataPtr; fragDataPtr.setNull();
  createTab_dih(signal, createTabPtr, fragDataPtr, &callback);
}

void
Dbdict::restartCreateTab_dihComplete(Signal* signal, 
				     Uint32 callbackData,
				     Uint32 returnCode){
  jam();
  
  CreateTableRecordPtr createTabPtr;  
  ndbrequire(c_opCreateTable.find(createTabPtr, callbackData));
  
  //@todo check error
  ndbrequire(createTabPtr.p->m_errorCode == 0);

  Callback callback;
  callback.m_callbackData = callbackData;
  callback.m_callbackFunction = 
    safe_cast(&Dbdict::restartCreateTab_activateComplete);
  
  alterTab_activate(signal, createTabPtr, &callback);
}

void
Dbdict::restartCreateTab_activateComplete(Signal* signal, 
					  Uint32 callbackData,
					  Uint32 returnCode){
  jam();
  
  CreateTableRecordPtr createTabPtr;  
  ndbrequire(c_opCreateTable.find(createTabPtr, callbackData));

  TableRecordPtr tabPtr;
  c_tableRecordPool.getPtr(tabPtr, createTabPtr.p->m_tablePtrI);
  tabPtr.p->tabState = TableRecord::DEFINED;
  
  c_opCreateTable.release(createTabPtr);

  c_restartRecord.activeTable++;
  checkSchemaStatus(signal);
}

void
Dbdict::restartDropTab(Signal* signal, Uint32 tableId){

  const Uint32 key = ++c_opRecordSequence;

  DropTableRecordPtr dropTabPtr;  
  ndbrequire(c_opDropTable.seize(dropTabPtr));
  
  dropTabPtr.p->key = key;
  c_opDropTable.add(dropTabPtr);
  
  dropTabPtr.p->m_errorCode = 0;
  dropTabPtr.p->m_request.tableId = tableId;
  dropTabPtr.p->m_coordinatorRef = 0;
  dropTabPtr.p->m_requestType = DropTabReq::RestartDropTab;
  dropTabPtr.p->m_participantData.m_gsn = GSN_DROP_TAB_REQ;
  

  dropTabPtr.p->m_participantData.m_block = 0;
  dropTabPtr.p->m_participantData.m_callback.m_callbackData = key;
  dropTabPtr.p->m_participantData.m_callback.m_callbackFunction = 
    safe_cast(&Dbdict::restartDropTab_complete);
  dropTab_nextStep(signal, dropTabPtr);  
}

void
Dbdict::restartDropTab_complete(Signal* signal, 
				Uint32 callbackData,
				Uint32 returnCode){
  jam();

  DropTableRecordPtr dropTabPtr;
  ndbrequire(c_opDropTable.find(dropTabPtr, callbackData));
  
  //@todo check error

  c_opDropTable.release(dropTabPtr);

  c_restartRecord.activeTable++;
  checkSchemaStatus(signal);
}

/* **************************************************************** */
/* ---------------------------------------------------------------- */
/* MODULE:          NODE FAILURE HANDLING ------------------------- */
/* ---------------------------------------------------------------- */
/*                                                                  */
/* This module contains the code that is used when nodes            */
/* (kernel/api) fails.                                              */
/* ---------------------------------------------------------------- */
/* **************************************************************** */

/* ---------------------------------------------------------------- */
// We receive a report of an API that failed.
/* ---------------------------------------------------------------- */
void Dbdict::execAPI_FAILREQ(Signal* signal) 
{
  jamEntry();
  Uint32 failedApiNode = signal->theData[0];
  BlockReference retRef = signal->theData[1];

#if 0
  Uint32 userNode = refToNode(c_connRecord.userBlockRef);
  if (userNode == failedApiNode) {
    jam();
    c_connRecord.userBlockRef = (Uint32)-1;
  }//if
#endif

  signal->theData[0] = failedApiNode;
  signal->theData[1] = reference();
  sendSignal(retRef, GSN_API_FAILCONF, signal, 2, JBB);
}//execAPI_FAILREQ()

/* ---------------------------------------------------------------- */
// We receive a report of one or more node failures of kernel nodes.
/* ---------------------------------------------------------------- */
void Dbdict::execNODE_FAILREP(Signal* signal) 
{
  jamEntry();
  NodeFailRep * const nodeFail = (NodeFailRep *)&signal->theData[0];

  c_failureNr    = nodeFail->failNo;
  const Uint32 numberOfFailedNodes  = nodeFail->noOfNodes;
  const bool masterFailed = (c_masterNodeId != nodeFail->masterNodeId);
  c_masterNodeId = nodeFail->masterNodeId;

  c_noNodesFailed += numberOfFailedNodes;
  Uint32 theFailedNodes[NodeBitmask::Size];
  memcpy(theFailedNodes, nodeFail->theNodes, sizeof(theFailedNodes));

  c_counterMgr.execNODE_FAILREP(signal);
  
  bool ok = false;
  switch(c_blockState){
  case BS_IDLE:
    jam();
    ok = true;
    if(c_opRecordPool.getSize() != c_opRecordPool.getNoOfFree()){
      jam();
      c_blockState = BS_NODE_FAILURE;
    }
    break;
  case BS_CREATE_TAB:
    jam();
    ok = true;
    if(!masterFailed)
      break;
    // fall through
  case BS_BUSY:
  case BS_NODE_FAILURE:
    jam();
    c_blockState = BS_NODE_FAILURE;
    ok = true;
    break;
  }
  ndbrequire(ok);
  
  for(unsigned i = 1; i < MAX_NDB_NODES; i++) {
    jam();
    if(NodeBitmask::get(theFailedNodes, i)) {
      jam();
      NodeRecordPtr nodePtr;
      c_nodes.getPtr(nodePtr, i);

      nodePtr.p->nodeState = NodeRecord::NDB_NODE_DEAD;
      NFCompleteRep * const nfCompRep = (NFCompleteRep *)&signal->theData[0];
      nfCompRep->blockNo      = DBDICT;
      nfCompRep->nodeId       = getOwnNodeId();
      nfCompRep->failedNodeId = nodePtr.i;
      sendSignal(DBDIH_REF, GSN_NF_COMPLETEREP, signal, 
		 NFCompleteRep::SignalLength, JBB);
      
      c_aliveNodes.clear(i);
    }//if
  }//for

}//execNODE_FAILREP()


/* **************************************************************** */
/* ---------------------------------------------------------------- */
/* MODULE:          NODE START HANDLING --------------------------- */
/* ---------------------------------------------------------------- */
/*                                                                  */
/* This module contains the code that is used when kernel nodes     */
/* starts.                                                          */
/* ---------------------------------------------------------------- */
/* **************************************************************** */

/* ---------------------------------------------------------------- */
// Include a starting node in list of nodes to be part of adding
// and dropping tables.
/* ---------------------------------------------------------------- */
void Dbdict::execINCL_NODEREQ(Signal* signal) 
{
  jamEntry();
  NodeRecordPtr nodePtr;
  BlockReference retRef = signal->theData[0];
  nodePtr.i = signal->theData[1];

  ndbrequire(c_noNodesFailed > 0);
  c_noNodesFailed--;

  c_nodes.getPtr(nodePtr);
  ndbrequire(nodePtr.p->nodeState == NodeRecord::NDB_NODE_DEAD);
  nodePtr.p->nodeState = NodeRecord::NDB_NODE_ALIVE;
  signal->theData[0] = reference();
  sendSignal(retRef, GSN_INCL_NODECONF, signal, 1, JBB);

  c_aliveNodes.set(nodePtr.i);
}//execINCL_NODEREQ()

/* **************************************************************** */
/* ---------------------------------------------------------------- */
/* MODULE:          ADD TABLE HANDLING ---------------------------- */
/* ---------------------------------------------------------------- */
/*                                                                  */
/* This module contains the code that is used when adding a table.  */
/* ---------------------------------------------------------------- */
/* **************************************************************** */

/* ---------------------------------------------------------------- */
// This signal receives information about a table from either:
// API, Ndbcntr or from other DICT.
/* ---------------------------------------------------------------- */
void
Dbdict::execCREATE_TABLE_REQ(Signal* signal){
  jamEntry();
  if(!assembleFragments(signal)){
    return;
  }
  
  CreateTableReq* const req = (CreateTableReq*)signal->getDataPtr();
  const Uint32 senderRef = req->senderRef;
  const Uint32 senderData = req->senderData;
  
  ParseDictTabInfoRecord parseRecord;
  do {
    if(getOwnNodeId() != c_masterNodeId){
      jam();
      parseRecord.errorCode = CreateTableRef::NotMaster;
      break;
    }
    
    if (c_blockState != BS_IDLE){
      jam();
      parseRecord.errorCode = CreateTableRef::Busy;
      break;
    }

    CreateTableRecordPtr createTabPtr;
    c_opCreateTable.seize(createTabPtr);
    
    if(createTabPtr.isNull()){
      jam();
      parseRecord.errorCode = CreateTableRef::Busy;
      break;
    }
    
    parseRecord.requestType = DictTabInfo::CreateTableFromAPI;
    parseRecord.errorCode = 0;
    
    SegmentedSectionPtr ptr;
    signal->getSection(ptr, CreateTableReq::DICT_TAB_INFO);
    SimplePropertiesSectionReader r(ptr, getSectionSegmentPool());
    
    handleTabInfoInit(r, &parseRecord);
    releaseSections(signal);
    
    if(parseRecord.errorCode != 0){
      jam();
      c_opCreateTable.release(createTabPtr);
      break;
    }
    
    createTabPtr.p->key = ++c_opRecordSequence;
    c_opCreateTable.add(createTabPtr);
    createTabPtr.p->m_errorCode = 0;
    createTabPtr.p->m_senderRef = senderRef;
    createTabPtr.p->m_senderData = senderData;
    createTabPtr.p->m_tablePtrI = parseRecord.tablePtr.i;
    createTabPtr.p->m_coordinatorRef = reference();
    createTabPtr.p->m_fragmentsPtrI = RNIL;
    createTabPtr.p->m_dihAddFragPtr = RNIL;

    Uint32 * theData = signal->getDataPtrSend();
    CreateFragmentationReq * const req = (CreateFragmentationReq*)theData;
    req->senderRef = reference();
    req->senderData = createTabPtr.p->key;
    req->fragmentationType = parseRecord.tablePtr.p->fragmentType;
    req->noOfFragments = 0;
    req->fragmentNode = 0;
    req->primaryTableId = RNIL;
    if (parseRecord.tablePtr.p->isOrderedIndex()) {
      // ordered index has same fragmentation as the table
      const Uint32 primaryTableId = parseRecord.tablePtr.p->primaryTableId;
      TableRecordPtr primaryTablePtr;
      c_tableRecordPool.getPtr(primaryTablePtr, primaryTableId);
      // fragmentationType must be consistent
      req->fragmentationType = primaryTablePtr.p->fragmentType;
      req->primaryTableId = primaryTableId;
    }
    sendSignal(DBDIH_REF, GSN_CREATE_FRAGMENTATION_REQ, signal,
	       CreateFragmentationReq::SignalLength, JBB);
    
    c_blockState = BS_CREATE_TAB;
    return;
  } while(0);
  
  /**
   * Something went wrong
   */
  releaseSections(signal);

  CreateTableRef * ref = (CreateTableRef*)signal->getDataPtrSend();
  ref->senderData = senderData;
  ref->senderRef = reference();
  ref->masterNodeId = c_masterNodeId;
  ref->errorCode = parseRecord.errorCode;
  ref->errorLine = parseRecord.errorLine;
  ref->errorKey = parseRecord.errorKey;
  ref->status = parseRecord.status;
  sendSignal(senderRef, GSN_CREATE_TABLE_REF, signal, 
	     CreateTableRef::SignalLength, JBB);
}

void
Dbdict::execALTER_TABLE_REQ(Signal* signal)
{
  // Received by master
  jamEntry();
  if(!assembleFragments(signal)){
    return;
  }
  AlterTableReq* const req = (AlterTableReq*)signal->getDataPtr();
  const Uint32 senderRef = req->senderRef;
  const Uint32 senderData = req->senderData;
  const Uint32 changeMask = req->changeMask;
  const Uint32 tableId = req->tableId;
  const Uint32 tableVersion = req->tableVersion;
  ParseDictTabInfoRecord* aParseRecord;
  
  // Get table definition
  TableRecordPtr tablePtr;
  c_tableRecordPool.getPtr(tablePtr, tableId, false);
  if(tablePtr.isNull()){
    jam();
    alterTableRef(signal, req, AlterTableRef::NoSuchTable);
    return;
  }
  
  if(getOwnNodeId() != c_masterNodeId){
    jam();
    alterTableRef(signal, req, AlterTableRef::NotMaster);
    return;
  }
  
  if(c_blockState != BS_IDLE){
    jam();
    alterTableRef(signal, req, AlterTableRef::Busy);
    return;
  }
  
  const TableRecord::TabState tabState = tablePtr.p->tabState;
  bool ok = false;
  switch(tabState){
  case TableRecord::NOT_DEFINED:
  case TableRecord::REORG_TABLE_PREPARED:
  case TableRecord::DEFINING:
  case TableRecord::CHECKED:
    jam();
    alterTableRef(signal, req, AlterTableRef::NoSuchTable);
    return;
  case TableRecord::DEFINED:
    ok = true;
    jam();
    break;
  case TableRecord::PREPARE_DROPPING:
  case TableRecord::DROPPING:
    jam();
    alterTableRef(signal, req, AlterTableRef::DropInProgress);
    return;
  }
  ndbrequire(ok);

  if(tablePtr.p->tableVersion != tableVersion){
    jam();
    alterTableRef(signal, req, AlterTableRef::InvalidTableVersion);
    return;
  }
  // Parse new table defintion
  ParseDictTabInfoRecord parseRecord;
  aParseRecord = &parseRecord;
    
  CreateTableRecordPtr alterTabPtr; // Reuse create table records
  c_opCreateTable.seize(alterTabPtr);
  CreateTableRecord * regAlterTabPtr =  alterTabPtr.p;
  
  if(alterTabPtr.isNull()){
    jam();
    alterTableRef(signal, req, AlterTableRef::Busy);
    return;
  }

  regAlterTabPtr->m_changeMask = changeMask;
  parseRecord.requestType = DictTabInfo::AlterTableFromAPI;
  parseRecord.errorCode = 0;
  
  SegmentedSectionPtr ptr;
  signal->getSection(ptr, AlterTableReq::DICT_TAB_INFO);
  SimplePropertiesSectionReader r(ptr, getSectionSegmentPool());

  handleTabInfoInit(r, &parseRecord, false); // Will not save info
  
  if(parseRecord.errorCode != 0){
    jam();
    c_opCreateTable.release(alterTabPtr);
    alterTableRef(signal, req, 
		  (AlterTableRef::ErrorCode) parseRecord.errorCode, 
		  aParseRecord);
    return;
  }
  
  releaseSections(signal);
  regAlterTabPtr->key = ++c_opRecordSequence;
  c_opCreateTable.add(alterTabPtr);
  ndbrequire(c_opCreateTable.find(alterTabPtr, regAlterTabPtr->key));
  regAlterTabPtr->m_errorCode = 0;
  regAlterTabPtr->m_senderRef = senderRef;
  regAlterTabPtr->m_senderData = senderData;
  regAlterTabPtr->m_tablePtrI = parseRecord.tablePtr.i;
  regAlterTabPtr->m_alterTableFailed = false;
  regAlterTabPtr->m_coordinatorRef = reference();
  regAlterTabPtr->m_fragmentsPtrI = RNIL;
  regAlterTabPtr->m_dihAddFragPtr = RNIL;

  // Alter table on all nodes
  c_blockState = BS_BUSY;

  // Send prepare request to all alive nodes
  SimplePropertiesSectionWriter w(getSectionSegmentPool());
  packTableIntoPagesImpl(w, parseRecord.tablePtr);
  
  SegmentedSectionPtr tabInfoPtr;
  w.getPtr(tabInfoPtr);
  signal->setSection(tabInfoPtr, AlterTabReq::DICT_TAB_INFO);
  
  NodeReceiverGroup rg(DBDICT, c_aliveNodes);
  regAlterTabPtr->m_coordinatorData.m_gsn = GSN_ALTER_TAB_REQ;
  SafeCounter safeCounter(c_counterMgr, regAlterTabPtr->m_coordinatorData.m_counter);
  safeCounter.init<AlterTabRef>(rg, regAlterTabPtr->key);

  AlterTabReq * const lreq = (AlterTabReq*)signal->getDataPtrSend();
  lreq->senderRef = reference();
  lreq->senderData = regAlterTabPtr->key;
  lreq->clientRef = regAlterTabPtr->m_senderRef;
  lreq->clientData = regAlterTabPtr->m_senderData;
  lreq->changeMask = changeMask;
  lreq->tableId = tableId;
  lreq->tableVersion = tableVersion + 1;
  lreq->gci = tablePtr.p->gciTableCreated;
  lreq->requestType = AlterTabReq::AlterTablePrepare;
  
  sendSignal(rg, GSN_ALTER_TAB_REQ, signal, 
	     AlterTabReq::SignalLength, JBB);
  
}

void Dbdict::alterTableRef(Signal * signal, 
			   AlterTableReq * req, 
			   AlterTableRef::ErrorCode errCode,
			   ParseDictTabInfoRecord* parseRecord)
{
  jam();
  releaseSections(signal);
  AlterTableRef * ref = (AlterTableRef*)signal->getDataPtrSend();
  Uint32 senderRef = req->senderRef;
  ref->senderData = req->senderData;
  ref->senderRef = reference();
  ref->masterNodeId = c_masterNodeId;
  if (parseRecord) {
    ref->errorCode = parseRecord->errorCode;
    ref->errorLine = parseRecord->errorLine;
    ref->errorKey = parseRecord->errorKey;
    ref->status = parseRecord->status;
  }
  else {
    ref->errorCode = errCode;
    ref->errorLine = 0;
    ref->errorKey = 0;
    ref->status = 0;
  }
  sendSignal(senderRef, GSN_ALTER_TABLE_REF, signal, 
	     AlterTableRef::SignalLength, JBB);
}

void
Dbdict::execALTER_TAB_REQ(Signal * signal) 
{
  // Received in all nodes to handle change locally
  jamEntry();

  if(!assembleFragments(signal)){
    return;
  }
  AlterTabReq* const req = (AlterTabReq*)signal->getDataPtr();
  const Uint32 senderRef = req->senderRef;
  const Uint32 senderData = req->senderData;
  const Uint32 changeMask = req->changeMask;
  const Uint32 tableId = req->tableId;
  const Uint32 tableVersion = req->tableVersion;
  const Uint32 gci = req->gci;
  AlterTabReq::RequestType requestType = 
    (AlterTabReq::RequestType) req->requestType;

  SegmentedSectionPtr tabInfoPtr;
  signal->getSection(tabInfoPtr, AlterTabReq::DICT_TAB_INFO);

  CreateTableRecordPtr alterTabPtr; // Reuse create table records

  if (senderRef != reference()) {
    jam();
    c_blockState = BS_BUSY;
  }
  if ((requestType == AlterTabReq::AlterTablePrepare)
      && (senderRef != reference())) {
    jam();
    c_opCreateTable.seize(alterTabPtr);
    if(!alterTabPtr.isNull())
      alterTabPtr.p->m_changeMask = changeMask;
  }
  else {
    jam();
    ndbrequire(c_opCreateTable.find(alterTabPtr, senderData));
  }
  if(alterTabPtr.isNull()){
    jam();
    alterTabRef(signal, req, AlterTableRef::Busy);
    return;
  }
  CreateTableRecord * regAlterTabPtr =  alterTabPtr.p;
  regAlterTabPtr->m_alterTableId = tableId;
  regAlterTabPtr->m_coordinatorRef = senderRef;
  
  // Get table definition
  TableRecordPtr tablePtr;
  c_tableRecordPool.getPtr(tablePtr, tableId, false);
  if(tablePtr.isNull()){
    jam();
    alterTabRef(signal, req, AlterTableRef::NoSuchTable);
    return;
  }
    
  switch(requestType) {
  case(AlterTabReq::AlterTablePrepare): {
    ParseDictTabInfoRecord* aParseRecord;
  
    const TableRecord::TabState tabState = tablePtr.p->tabState;
    bool ok = false;
    switch(tabState){
    case TableRecord::NOT_DEFINED:
    case TableRecord::REORG_TABLE_PREPARED:
    case TableRecord::DEFINING:
    case TableRecord::CHECKED:
      jam();
      alterTabRef(signal, req, AlterTableRef::NoSuchTable);
      return;
    case TableRecord::DEFINED:
      ok = true;
      jam();
      break;
    case TableRecord::PREPARE_DROPPING:
    case TableRecord::DROPPING:
      jam();
      alterTabRef(signal, req, AlterTableRef::DropInProgress);
      return;
    }
    ndbrequire(ok);

    if(tablePtr.p->tableVersion + 1 != tableVersion){
      jam();
      alterTabRef(signal, req, AlterTableRef::InvalidTableVersion);
      return;
    }
    TableRecordPtr newTablePtr;
    if (senderRef  != reference()) {
      jam();
      // Parse altered table defintion
      ParseDictTabInfoRecord parseRecord;
      aParseRecord = &parseRecord;
      
      parseRecord.requestType = DictTabInfo::AlterTableFromAPI;
      parseRecord.errorCode = 0;
      
      SimplePropertiesSectionReader r(tabInfoPtr, getSectionSegmentPool());
      
      handleTabInfoInit(r, &parseRecord, false); // Will not save info
      
      if(parseRecord.errorCode != 0){
	jam();
	c_opCreateTable.release(alterTabPtr);
	alterTabRef(signal, req, 
		    (AlterTableRef::ErrorCode) parseRecord.errorCode, 
		    aParseRecord);
	return;
      }
      regAlterTabPtr->key = senderData;
      c_opCreateTable.add(alterTabPtr);
      regAlterTabPtr->m_errorCode = 0;
      regAlterTabPtr->m_senderRef = senderRef;
      regAlterTabPtr->m_senderData = senderData;
      regAlterTabPtr->m_tablePtrI = parseRecord.tablePtr.i;
      regAlterTabPtr->m_fragmentsPtrI = RNIL;
      regAlterTabPtr->m_dihAddFragPtr = RNIL;
      newTablePtr = parseRecord.tablePtr;
      newTablePtr.p->tableVersion = tableVersion;
    }
    else { // (req->senderRef  == reference())
      jam();
      c_tableRecordPool.getPtr(newTablePtr, regAlterTabPtr->m_tablePtrI);
      newTablePtr.p->tableVersion = tableVersion;
    }
    if (handleAlterTab(req, regAlterTabPtr, tablePtr, newTablePtr) == -1) {
      jam();
      c_opCreateTable.release(alterTabPtr);
      alterTabRef(signal, req, AlterTableRef::UnsupportedChange);
      return;
    }
    releaseSections(signal);
    // Propagate alter table to other local blocks
    AlterTabReq * req = (AlterTabReq*)signal->getDataPtrSend();
    req->senderRef = reference();
    req->senderData = senderData;
    req->changeMask = changeMask;
    req->tableId = tableId;
    req->tableVersion = tableVersion;
    req->gci = gci;
    req->requestType = requestType;
    sendSignal(DBLQH_REF, GSN_ALTER_TAB_REQ, signal, 
	       AlterTabReq::SignalLength, JBB);	
    return;
  }
  case(AlterTabReq::AlterTableCommit): {
    jam();
    // Write schema for altered table to disk
    SegmentedSectionPtr tabInfoPtr;
    signal->getSection(tabInfoPtr, AlterTabReq::DICT_TAB_INFO);
    regAlterTabPtr->m_tabInfoPtrI = tabInfoPtr.i;
    
    signal->header.m_noOfSections = 0;

    // Update table record
    tablePtr.p->packedSize = tabInfoPtr.sz;
    tablePtr.p->tableVersion = tableVersion;
    tablePtr.p->gciTableCreated = gci;

    SchemaFile::TableEntry tabEntry;
    tabEntry.m_tableVersion = tableVersion;
    tabEntry.m_tableType    = tablePtr.p->tableType;
    tabEntry.m_tableState   = SchemaFile::ALTER_TABLE_COMMITTED;
    tabEntry.m_gcp          = gci;
    tabEntry.m_noOfPages    = 
      DIV(tabInfoPtr.sz + ZPAGE_HEADER_SIZE, ZSIZE_OF_PAGES_IN_WORDS);
    
    Callback callback;
    callback.m_callbackData = senderData;
    callback.m_callbackFunction = 
      safe_cast(&Dbdict::alterTab_writeSchemaConf);
    
    updateSchemaState(signal, tableId, &tabEntry, &callback);
    break;
  }
  case(AlterTabReq::AlterTableRevert): {
    jam();
    // Revert failed alter table
    revertAlterTable(signal, changeMask, tableId, regAlterTabPtr);
    // Acknowledge the reverted alter table
    AlterTabConf * conf = (AlterTabConf*)signal->getDataPtrSend();
    conf->senderRef = reference();
    conf->senderData = senderData;
    conf->changeMask = changeMask;
    conf->tableId = tableId;
    conf->tableVersion = tableVersion;
    conf->gci = gci;
    conf->requestType = requestType;
    sendSignal(senderRef, GSN_ALTER_TAB_CONF, signal, 
	       AlterTabConf::SignalLength, JBB);
    break;
  }
  default: ndbrequire(false);
  }
}

void Dbdict::alterTabRef(Signal * signal, 
			 AlterTabReq * req, 
			 AlterTableRef::ErrorCode errCode,
			 ParseDictTabInfoRecord* parseRecord)
{
  jam();
  releaseSections(signal);
  AlterTabRef * ref = (AlterTabRef*)signal->getDataPtrSend();
  Uint32 senderRef = req->senderRef;
  ref->senderData = req->senderData;
  ref->senderRef = reference();
  if (parseRecord) {
    jam();
    ref->errorCode = parseRecord->errorCode;
    ref->errorLine = parseRecord->errorLine;
    ref->errorKey = parseRecord->errorKey;
    ref->errorStatus = parseRecord->status;
  }
  else {
    jam();
    ref->errorCode = errCode;
    ref->errorLine = 0;
    ref->errorKey = 0;
    ref->errorStatus = 0;
  }
  sendSignal(senderRef, GSN_ALTER_TAB_REF, signal, 
	     AlterTabRef::SignalLength, JBB);
  
  c_blockState = BS_IDLE;
}

void Dbdict::execALTER_TAB_REF(Signal * signal){
  jamEntry();

  AlterTabRef * ref = (AlterTabRef*)signal->getDataPtr();

  Uint32 senderRef = ref->senderRef;
  Uint32 senderData = ref->senderData;
  Uint32 errorCode = ref->errorCode;
  Uint32 errorLine = ref->errorLine;
  Uint32 errorKey = ref->errorKey;
  Uint32 errorStatus = ref->errorStatus;
  AlterTabReq::RequestType requestType = 
    (AlterTabReq::RequestType) ref->requestType;
  CreateTableRecordPtr alterTabPtr;  
  ndbrequire(c_opCreateTable.find(alterTabPtr, senderData));
  CreateTableRecord * regAlterTabPtr =  alterTabPtr.p;
  Uint32 changeMask = regAlterTabPtr->m_changeMask;
  SafeCounter safeCounter(c_counterMgr, regAlterTabPtr->m_coordinatorData.m_counter);
  safeCounter.clearWaitingFor(refToNode(senderRef));
  switch (requestType) {
  case(AlterTabReq::AlterTablePrepare): {
    if (safeCounter.done()) {
      jam();
      // Send revert request to all alive nodes
      TableRecordPtr tablePtr;
      c_tableRecordPool.getPtr(tablePtr, regAlterTabPtr->m_alterTableId);
      Uint32 tableId = tablePtr.p->tableId;
      Uint32 tableVersion = tablePtr.p->tableVersion;
      Uint32 gci = tablePtr.p->gciTableCreated;
      SimplePropertiesSectionWriter w(getSectionSegmentPool());
      packTableIntoPagesImpl(w, tablePtr);
      SegmentedSectionPtr spDataPtr;
      w.getPtr(spDataPtr);
      signal->setSection(spDataPtr, AlterTabReq::DICT_TAB_INFO);
      
      NodeReceiverGroup rg(DBDICT, c_aliveNodes);
      regAlterTabPtr->m_coordinatorData.m_gsn = GSN_ALTER_TAB_REQ;
      safeCounter.init<AlterTabRef>(rg, regAlterTabPtr->key);
  
      AlterTabReq * const lreq = (AlterTabReq*)signal->getDataPtrSend();
      lreq->senderRef = reference();
      lreq->senderData = regAlterTabPtr->key;
      lreq->clientRef = regAlterTabPtr->m_senderRef;
      lreq->clientData = regAlterTabPtr->m_senderData;
      lreq->changeMask = changeMask;
      lreq->tableId = tableId;
      lreq->tableVersion = tableVersion;
      lreq->gci = gci;
      lreq->requestType = AlterTabReq::AlterTableRevert;
      
      sendSignal(rg, GSN_ALTER_TAB_REQ, signal, 
		 AlterTabReq::SignalLength, JBB);
    }
    else {
      jam();
      regAlterTabPtr->m_alterTableFailed = true;
    }
    break;
  }
  case(AlterTabReq::AlterTableCommit):
    jam();
  case(AlterTabReq::AlterTableRevert): {
    AlterTableRef * apiRef = (AlterTableRef*)signal->getDataPtrSend();
    
    apiRef->senderData = senderData;
    apiRef->senderRef = reference();
    apiRef->masterNodeId = c_masterNodeId;
    apiRef->errorCode = errorCode;
    apiRef->errorLine = errorLine;
    apiRef->errorKey = errorKey;
    apiRef->status = errorStatus;
    if (safeCounter.done()) {
      jam();
      sendSignal(senderRef, GSN_ALTER_TABLE_REF, signal, 
		 AlterTableRef::SignalLength, JBB);
      c_blockState = BS_IDLE;
    }
    else {
      jam();
      regAlterTabPtr->m_alterTableFailed = true;
      regAlterTabPtr->m_alterTableRef = *apiRef;
    }
    break;
  } 
  default: ndbrequire(false);
  }
}

void
Dbdict::execALTER_TAB_CONF(Signal * signal){
  jamEntry();
  AlterTabConf * const conf = (AlterTabConf*)signal->getDataPtr();
  Uint32 senderRef = conf->senderRef;
  Uint32 senderData = conf->senderData;
  Uint32 changeMask = conf->changeMask;
  Uint32 tableId = conf->tableId;
  Uint32 tableVersion = conf->tableVersion;
  Uint32 gci = conf->gci;
  AlterTabReq::RequestType requestType = 
    (AlterTabReq::RequestType) conf->requestType;
  CreateTableRecordPtr alterTabPtr;  
  ndbrequire(c_opCreateTable.find(alterTabPtr, senderData));
  CreateTableRecord * regAlterTabPtr =  alterTabPtr.p;

  switch (requestType) {
  case(AlterTabReq::AlterTablePrepare): {
    switch(refToBlock(signal->getSendersBlockRef())) {
    case DBLQH: {
      jam();
      AlterTabReq * req = (AlterTabReq*)signal->getDataPtrSend();
      req->senderRef = reference();
      req->senderData = senderData;
      req->changeMask = changeMask;
      req->tableId = tableId;
      req->tableVersion = tableVersion;
      req->gci = gci;
      req->requestType = requestType;
      sendSignal(DBDIH_REF, GSN_ALTER_TAB_REQ, signal, 
		 AlterTabReq::SignalLength, JBB);	
      return;
    }
    case DBDIH: {
      jam();
      AlterTabReq * req = (AlterTabReq*)signal->getDataPtrSend();
      req->senderRef = reference();
      req->senderData = senderData;
      req->changeMask = changeMask;
      req->tableId = tableId;
      req->tableVersion = tableVersion;
      req->gci = gci;
      req->requestType = requestType;
      sendSignal(DBTC_REF, GSN_ALTER_TAB_REQ, signal, 
		 AlterTabReq::SignalLength, JBB);	
      return;
    }
    case DBTC: {
      jam();
      // Participant is done with prepare phase, send conf to coordinator
      AlterTabConf * conf = (AlterTabConf*)signal->getDataPtrSend();
      conf->senderRef = reference();
      conf->senderData = senderData;
      conf->changeMask = changeMask;
      conf->tableId = tableId;
      conf->tableVersion = tableVersion;
      conf->gci = gci;
      conf->requestType = requestType;
      sendSignal(regAlterTabPtr->m_coordinatorRef, GSN_ALTER_TAB_CONF, signal, 
		 AlterTabConf::SignalLength, JBB);
      return;
    }
    default :break;
    }
    // Coordinator only
    SafeCounter safeCounter(c_counterMgr, regAlterTabPtr->m_coordinatorData.m_counter);
    safeCounter.clearWaitingFor(refToNode(senderRef));
    if (safeCounter.done()) {
      jam();
      // We have received all local confirmations
      if (regAlterTabPtr->m_alterTableFailed) {
	jam();
	// Send revert request to all alive nodes
	TableRecordPtr tablePtr;
	c_tableRecordPool.getPtr(tablePtr, regAlterTabPtr->m_alterTableId);
	Uint32 tableId = tablePtr.p->tableId;
	Uint32 tableVersion = tablePtr.p->tableVersion;
	Uint32 gci = tablePtr.p->gciTableCreated;
	SimplePropertiesSectionWriter w(getSectionSegmentPool());
	packTableIntoPagesImpl(w, tablePtr);
	SegmentedSectionPtr spDataPtr;
	w.getPtr(spDataPtr);
	signal->setSection(spDataPtr, AlterTabReq::DICT_TAB_INFO);
	
	NodeReceiverGroup rg(DBDICT, c_aliveNodes);
	regAlterTabPtr->m_coordinatorData.m_gsn = GSN_ALTER_TAB_REQ;
	safeCounter.init<AlterTabRef>(rg, regAlterTabPtr->key);
	
	AlterTabReq * const lreq = (AlterTabReq*)signal->getDataPtrSend();
	lreq->senderRef = reference();
	lreq->senderData = regAlterTabPtr->key;
	lreq->clientRef = regAlterTabPtr->m_senderRef;
	lreq->clientData = regAlterTabPtr->m_senderData;
	lreq->changeMask = changeMask;
	lreq->tableId = tableId;
	lreq->tableVersion = tableVersion;
	lreq->gci = gci;
	lreq->requestType = AlterTabReq::AlterTableRevert;
	
	sendSignal(rg, GSN_ALTER_TAB_REQ, signal, 
		   AlterTabReq::SignalLength, JBB);
      }
      else {
	jam();
	// Send commit request to all alive nodes
	TableRecordPtr tablePtr;
	c_tableRecordPool.getPtr(tablePtr, tableId);
	SimplePropertiesSectionWriter w(getSectionSegmentPool());
	packTableIntoPagesImpl(w, tablePtr);
	SegmentedSectionPtr spDataPtr;
	w.getPtr(spDataPtr);
	signal->setSection(spDataPtr, AlterTabReq::DICT_TAB_INFO);
	
	NodeReceiverGroup rg(DBDICT, c_aliveNodes);
	regAlterTabPtr->m_coordinatorData.m_gsn = GSN_ALTER_TAB_REQ;
	safeCounter.init<AlterTabRef>(rg, regAlterTabPtr->key);
  	
	AlterTabReq * const lreq = (AlterTabReq*)signal->getDataPtrSend();
	lreq->senderRef = reference();
	lreq->senderData = regAlterTabPtr->key;
	lreq->clientRef = regAlterTabPtr->m_senderRef;
	lreq->clientData = regAlterTabPtr->m_senderData;
	lreq->changeMask = changeMask;
	lreq->tableId = tableId;
	lreq->tableVersion = tableVersion;
	lreq->gci = gci;
	lreq->requestType = AlterTabReq::AlterTableCommit;
	
	sendSignal(rg, GSN_ALTER_TAB_REQ, signal, 
		   AlterTabReq::SignalLength, JBB);
      }
    }
    else {
      // (!safeCounter.done())
      jam();
    }
    break;
  }
  case(AlterTabReq::AlterTableRevert):
    jam();
  case(AlterTabReq::AlterTableCommit): {
    SafeCounter safeCounter(c_counterMgr, regAlterTabPtr->m_coordinatorData.m_counter);
    safeCounter.clearWaitingFor(refToNode(senderRef));
    if (safeCounter.done()) {
      jam();
      // We have received all local confirmations
      releaseSections(signal);
      if (regAlterTabPtr->m_alterTableFailed) {
	jam();
	AlterTableRef * apiRef = 
	  (AlterTableRef*)signal->getDataPtrSend();
	*apiRef = regAlterTabPtr->m_alterTableRef;
	sendSignal(regAlterTabPtr->m_senderRef, GSN_ALTER_TABLE_REF, signal, 
		   AlterTableRef::SignalLength, JBB);	
      }
      else {
	jam();
	// Alter table completed, inform API
	AlterTableConf * const apiConf = 
	  (AlterTableConf*)signal->getDataPtrSend();
	apiConf->senderRef = reference();
	apiConf->senderData = regAlterTabPtr->m_senderData;
	apiConf->tableId = tableId;
	apiConf->tableVersion = tableVersion;
	
	//@todo check api failed
	sendSignal(regAlterTabPtr->m_senderRef, GSN_ALTER_TABLE_CONF, signal,
		   AlterTableConf::SignalLength, JBB);
      }
      
      // Release resources
      TableRecordPtr tabPtr;
      c_tableRecordPool.getPtr(tabPtr, regAlterTabPtr->m_tablePtrI);  
      releaseTableObject(tabPtr.i, false);
      c_opCreateTable.release(alterTabPtr);
      c_blockState = BS_IDLE;
    }
    else {
      // (!safeCounter.done())
      jam();
    }
    break;
  }
  default: ndbrequire(false);
  }
}

// For debugging
inline
void Dbdict::printTables()
{
  DLHashTable<TableRecord>::Iterator iter;
  bool moreTables = c_tableRecordHash.first(iter);
  printf("TABLES IN DICT:\n");
  while (moreTables) {
    TableRecordPtr tablePtr = iter.curr;
    printf("%s ", tablePtr.p->tableName);
    moreTables = c_tableRecordHash.next(iter);
  }
  printf("\n");
}

int Dbdict::handleAlterTab(AlterTabReq * req,
			   CreateTableRecord * regAlterTabPtr,
			   TableRecordPtr origTablePtr,
			   TableRecordPtr newTablePtr)
{
  Uint32 changeMask = req->changeMask;
  
  if (AlterTableReq::getNameFlag(changeMask)) {
    jam();
    // Table rename
    // Remove from hashtable
#ifdef VM_TRACE
    TableRecordPtr tmp;
    ndbrequire(c_tableRecordHash.find(tmp, *origTablePtr.p));
#endif
    c_tableRecordHash.remove(origTablePtr);
    strcpy(regAlterTabPtr->previousTableName, origTablePtr.p->tableName);
    strcpy(origTablePtr.p->tableName, newTablePtr.p->tableName);
    // Set new schema version
    origTablePtr.p->tableVersion = newTablePtr.p->tableVersion;
    // Put it back
#ifdef VM_TRACE
    ndbrequire(!c_tableRecordHash.find(tmp, *origTablePtr.p));
#endif
    c_tableRecordHash.add(origTablePtr);	 
    
    return 0;
  }
  jam();
  return -1;
}

void Dbdict::revertAlterTable(Signal * signal, 
			      Uint32 changeMask, 
			      Uint32 tableId,
			      CreateTableRecord * regAlterTabPtr)
{
  if (AlterTableReq::getNameFlag(changeMask)) {
    jam();
    // Table rename
    // Restore previous name
    TableRecordPtr tablePtr;
    c_tableRecordPool.getPtr(tablePtr, tableId);
    // Remove from hashtable
#ifdef VM_TRACE
    TableRecordPtr tmp;
    ndbrequire(c_tableRecordHash.find(tmp, * tablePtr.p));
#endif
    c_tableRecordHash.remove(tablePtr);
    // Restore name
    strcpy(tablePtr.p->tableName, regAlterTabPtr->previousTableName);
    // Revert schema version
    tablePtr.p->tableVersion = tablePtr.p->tableVersion - 1;
    // Put it back
#ifdef VM_TRACE
    ndbrequire(!c_tableRecordHash.find(tmp, * tablePtr.p));
#endif
    c_tableRecordHash.add(tablePtr);	 

    return;
  }

  ndbrequire(false);
}

void
Dbdict::alterTab_writeSchemaConf(Signal* signal, 
				 Uint32 callbackData,
				 Uint32 returnCode)
{
  jam();
  Uint32 key = callbackData;
  CreateTableRecordPtr alterTabPtr;  
  ndbrequire(c_opCreateTable.find(alterTabPtr, key));
  CreateTableRecord * regAlterTabPtr =  alterTabPtr.p;
  Uint32 tableId = regAlterTabPtr->m_alterTableId;

  Callback callback;
  callback.m_callbackData = regAlterTabPtr->key;
  callback.m_callbackFunction = 
    safe_cast(&Dbdict::alterTab_writeTableConf);
  
  SegmentedSectionPtr tabInfoPtr;
  getSection(tabInfoPtr, regAlterTabPtr->m_tabInfoPtrI);
  
  writeTableFile(signal, tableId, tabInfoPtr, &callback);

  signal->setSection(tabInfoPtr, 0);
  releaseSections(signal);
}

void
Dbdict::alterTab_writeTableConf(Signal* signal, 
				Uint32 callbackData,
				Uint32 returnCode)
{
  jam();
  CreateTableRecordPtr alterTabPtr;  
  ndbrequire(c_opCreateTable.find(alterTabPtr, callbackData));
  CreateTableRecord * regAlterTabPtr =  alterTabPtr.p;
  Uint32 coordinatorRef = regAlterTabPtr->m_coordinatorRef;
  TableRecordPtr tabPtr;
  c_tableRecordPool.getPtr(tabPtr, regAlterTabPtr->m_alterTableId);

  // Alter table commit request handled successfully 
  AlterTabConf * conf = (AlterTabConf*)signal->getDataPtrSend();
  conf->senderRef = reference();
  conf->senderData = callbackData;
  conf->tableId = tabPtr.p->tableId;
  conf->tableVersion = tabPtr.p->tableVersion;
  conf->gci = tabPtr.p->gciTableCreated;
  conf->requestType = AlterTabReq::AlterTableCommit;
  sendSignal(coordinatorRef, GSN_ALTER_TAB_CONF, signal, 
	       AlterTabConf::SignalLength, JBB);
  if(coordinatorRef != reference()) {
    jam();
    // Release resources
    c_tableRecordPool.getPtr(tabPtr, regAlterTabPtr->m_tablePtrI);  
    releaseTableObject(tabPtr.i, false);
    c_opCreateTable.release(alterTabPtr);
    c_blockState = BS_IDLE;
  }
}

void
Dbdict::execCREATE_FRAGMENTATION_REF(Signal * signal){
  jamEntry();
  const Uint32 * theData = signal->getDataPtr();
  CreateFragmentationRef * const ref = (CreateFragmentationRef*)theData;
  (void)ref;
  ndbrequire(false);
}

void
Dbdict::execCREATE_FRAGMENTATION_CONF(Signal* signal){
  jamEntry();
  const Uint32 * theData = signal->getDataPtr();
  CreateFragmentationConf * const conf = (CreateFragmentationConf*)theData;

  CreateTableRecordPtr createTabPtr;
  ndbrequire(c_opCreateTable.find(createTabPtr, conf->senderData));

  ndbrequire(signal->getNoOfSections() == 1);

  SegmentedSectionPtr fragDataPtr;
  signal->getSection(fragDataPtr, CreateFragmentationConf::FRAGMENTS);
  signal->header.m_noOfSections = 0;

  /**
   * Get table
   */
  TableRecordPtr tabPtr;
  c_tableRecordPool.getPtr(tabPtr, createTabPtr.p->m_tablePtrI);

  /**
   * Save fragment count
   */
  tabPtr.p->fragmentCount = conf->noOfFragments;

  /**
   * Update table version
   */
  PageRecordPtr pagePtr;
  c_pageRecordArray.getPtr(pagePtr, c_schemaRecord.schemaPage);
  SchemaFile::TableEntry * tabEntry = getTableEntry(pagePtr.p, tabPtr.i);

  tabPtr.p->tableVersion = tabEntry->m_tableVersion + 1;

  /**
   * Pack
   */
  SimplePropertiesSectionWriter w(getSectionSegmentPool());
  packTableIntoPagesImpl(w, tabPtr);
  
  SegmentedSectionPtr spDataPtr;
  w.getPtr(spDataPtr);
  
  signal->setSection(spDataPtr, CreateTabReq::DICT_TAB_INFO);
  signal->setSection(fragDataPtr, CreateTabReq::FRAGMENTATION);
  
  NodeReceiverGroup rg(DBDICT, c_aliveNodes);
  SafeCounter tmp(c_counterMgr, createTabPtr.p->m_coordinatorData.m_counter);
  createTabPtr.p->m_coordinatorData.m_gsn = GSN_CREATE_TAB_REQ;
  createTabPtr.p->m_coordinatorData.m_requestType = CreateTabReq::CreateTablePrepare;
  tmp.init<CreateTabRef>(rg, GSN_CREATE_TAB_REF, createTabPtr.p->key);
  
  CreateTabReq * const req = (CreateTabReq*)theData;
  req->senderRef = reference();
  req->senderData = createTabPtr.p->key;
  req->clientRef = createTabPtr.p->m_senderRef;
  req->clientData = createTabPtr.p->m_senderData;
  req->requestType = CreateTabReq::CreateTablePrepare;

  req->gci = 0;
  req->tableId = tabPtr.i;
  req->tableVersion = tabEntry->m_tableVersion + 1;
  
  sendFragmentedSignal(rg, GSN_CREATE_TAB_REQ, signal, 
		       CreateTabReq::SignalLength, JBB);

  return;
}

void
Dbdict::execCREATE_TAB_REF(Signal* signal){
  jamEntry();

  CreateTabRef * const ref = (CreateTabRef*)signal->getDataPtr();
  
  CreateTableRecordPtr createTabPtr;
  ndbrequire(c_opCreateTable.find(createTabPtr, ref->senderData));
  
  ndbrequire(createTabPtr.p->m_coordinatorRef == reference());
  ndbrequire(createTabPtr.p->m_coordinatorData.m_gsn == GSN_CREATE_TAB_REQ);

  if(ref->errorCode != CreateTabRef::NF_FakeErrorREF){
    createTabPtr.p->setErrorCode(ref->errorCode);
  }
  createTab_reply(signal, createTabPtr, refToNode(ref->senderRef));
}

void
Dbdict::execCREATE_TAB_CONF(Signal* signal){
  jamEntry();

  ndbrequire(signal->getNoOfSections() == 0);

  CreateTabConf * const conf = (CreateTabConf*)signal->getDataPtr();
  
  CreateTableRecordPtr createTabPtr;
  ndbrequire(c_opCreateTable.find(createTabPtr, conf->senderData));
  
  ndbrequire(createTabPtr.p->m_coordinatorRef == reference());
  ndbrequire(createTabPtr.p->m_coordinatorData.m_gsn == GSN_CREATE_TAB_REQ);

  createTab_reply(signal, createTabPtr, refToNode(conf->senderRef));
}

void
Dbdict::createTab_reply(Signal* signal, 
			CreateTableRecordPtr createTabPtr, 
			Uint32 nodeId)
{

  SafeCounter tmp(c_counterMgr, createTabPtr.p->m_coordinatorData.m_counter);
  if(!tmp.clearWaitingFor(nodeId)){
    jam();
    return;
  }
  
  switch(createTabPtr.p->m_coordinatorData.m_requestType){
  case CreateTabReq::CreateTablePrepare:{

    if(createTabPtr.p->m_errorCode != 0){
      jam();
      /**
       * Failed to prepare on atleast one node -> abort on all
       */
      NodeReceiverGroup rg(DBDICT, c_aliveNodes);
      createTabPtr.p->m_coordinatorData.m_gsn = GSN_CREATE_TAB_REQ;
      createTabPtr.p->m_coordinatorData.m_requestType = CreateTabReq::CreateTableDrop;
      ndbrequire(tmp.init<CreateTabRef>(rg, createTabPtr.p->key));
      
      CreateTabReq * const req = (CreateTabReq*)signal->getDataPtrSend();
      req->senderRef = reference();
      req->senderData = createTabPtr.p->key;
      req->requestType = CreateTabReq::CreateTableDrop;
      
      sendSignal(rg, GSN_CREATE_TAB_REQ, signal, 
		 CreateTabReq::SignalLength, JBB);
      return;
    }
    
    /**
     * Lock mutex before commiting table
     */
    Mutex mutex(signal, c_mutexMgr, createTabPtr.p->m_startLcpMutex);
    Callback c = { safe_cast(&Dbdict::createTab_startLcpMutex_locked),
		   createTabPtr.p->key};

    ndbrequire(mutex.lock(c));
    return;
  }
  case CreateTabReq::CreateTableCommit:{
    jam();
    ndbrequire(createTabPtr.p->m_errorCode == 0);
    
    /**
     * Unlock mutex before commiting table
     */
    Mutex mutex(signal, c_mutexMgr, createTabPtr.p->m_startLcpMutex);
    Callback c = { safe_cast(&Dbdict::createTab_startLcpMutex_unlocked),
		   createTabPtr.p->key};
    mutex.unlock(c);
    return;
  }
  case CreateTabReq::CreateTableDrop:{
    jam();
    CreateTableRef * const ref = (CreateTableRef*)signal->getDataPtr();
    ref->senderRef = reference();
    ref->senderData = createTabPtr.p->m_senderData;
    ref->errorCode = createTabPtr.p->m_errorCode;
    ref->masterNodeId = c_masterNodeId;
    ref->status = 0;
    ref->errorKey = 0;
    ref->errorLine = 0;
    
    //@todo check api failed
    sendSignal(createTabPtr.p->m_senderRef, GSN_CREATE_TABLE_REF, signal, 
	       CreateTableRef::SignalLength, JBB);
    c_opCreateTable.release(createTabPtr);
    c_blockState = BS_IDLE;
    return;
  }
  }
  ndbrequire(false);
}

void
Dbdict::createTab_startLcpMutex_locked(Signal* signal, 
				       Uint32 callbackData,
				       Uint32 retValue){
  jamEntry();

  ndbrequire(retValue == 0);
  
  CreateTableRecordPtr createTabPtr;  
  ndbrequire(c_opCreateTable.find(createTabPtr, callbackData));
  
  NodeReceiverGroup rg(DBDICT, c_aliveNodes);
  createTabPtr.p->m_coordinatorData.m_gsn = GSN_CREATE_TAB_REQ;
  createTabPtr.p->m_coordinatorData.m_requestType = CreateTabReq::CreateTableCommit;
  SafeCounter tmp(c_counterMgr, createTabPtr.p->m_coordinatorData.m_counter);
  tmp.init<CreateTabRef>(rg, GSN_CREATE_TAB_REF, createTabPtr.p->key);
  
  CreateTabReq * const req = (CreateTabReq*)signal->getDataPtrSend();
  req->senderRef = reference();
  req->senderData = createTabPtr.p->key;
  req->requestType = CreateTabReq::CreateTableCommit;
  
  sendSignal(rg, GSN_CREATE_TAB_REQ, signal, 
	     CreateTabReq::SignalLength, JBB);
}

void
Dbdict::createTab_startLcpMutex_unlocked(Signal* signal, 
					 Uint32 callbackData,
					 Uint32 retValue){
  jamEntry();
  
  ndbrequire(retValue == 0);
  
  CreateTableRecordPtr createTabPtr;  
  ndbrequire(c_opCreateTable.find(createTabPtr, callbackData));

  createTabPtr.p->m_startLcpMutex.release(c_mutexMgr);
  
  TableRecordPtr tabPtr;
  c_tableRecordPool.getPtr(tabPtr, createTabPtr.p->m_tablePtrI);
  
  CreateTableConf * const conf = (CreateTableConf*)signal->getDataPtr();
  conf->senderRef = reference();
  conf->senderData = createTabPtr.p->m_senderData;
  conf->tableId = createTabPtr.p->m_tablePtrI;
  conf->tableVersion = tabPtr.p->tableVersion;
  
  //@todo check api failed
  sendSignal(createTabPtr.p->m_senderRef, GSN_CREATE_TABLE_CONF, signal, 
	     CreateTableConf::SignalLength, JBB);
  c_opCreateTable.release(createTabPtr);
  c_blockState = BS_IDLE;
  return;
}

/***********************************************************
 * CreateTable participant code
 **********************************************************/
void
Dbdict::execCREATE_TAB_REQ(Signal* signal){
  jamEntry();

  if(!assembleFragments(signal)){
    jam();
    return;
  }

  CreateTabReq * const req = (CreateTabReq*)signal->getDataPtr();

  CreateTabReq::RequestType rt = (CreateTabReq::RequestType)req->requestType;
  switch(rt){
  case CreateTabReq::CreateTablePrepare:
    CRASH_INSERTION2(6003, getOwnNodeId() != c_masterNodeId);
    createTab_prepare(signal, req);
    return;
  case CreateTabReq::CreateTableCommit:
    CRASH_INSERTION2(6004, getOwnNodeId() != c_masterNodeId);
    createTab_commit(signal, req);
    return;
  case CreateTabReq::CreateTableDrop:
    CRASH_INSERTION2(6005, getOwnNodeId() != c_masterNodeId);
    createTab_drop(signal, req);
    return;
  }
  ndbrequire(false);
}

void
Dbdict::createTab_prepare(Signal* signal, CreateTabReq * req){

  const Uint32 gci = req->gci;
  const Uint32 tableId = req->tableId;
  const Uint32 tableVersion = req->tableVersion;

  SegmentedSectionPtr tabInfoPtr;
  signal->getSection(tabInfoPtr, CreateTabReq::DICT_TAB_INFO);
  
  CreateTableRecordPtr createTabPtr;  
  if(req->senderRef == reference()){
    jam();
    ndbrequire(c_opCreateTable.find(createTabPtr, req->senderData));
  } else {
    jam();
    c_opCreateTable.seize(createTabPtr);
    
    ndbrequire(!createTabPtr.isNull());
    
    createTabPtr.p->key = req->senderData;
    c_opCreateTable.add(createTabPtr);
    createTabPtr.p->m_errorCode = 0;
    createTabPtr.p->m_tablePtrI = tableId;
    createTabPtr.p->m_coordinatorRef = req->senderRef;
    createTabPtr.p->m_senderRef = req->clientRef;
    createTabPtr.p->m_senderData = req->clientData;
    createTabPtr.p->m_dihAddFragPtr = RNIL;
    
    /**
     * Put data into table record
     */
    ParseDictTabInfoRecord parseRecord;
    parseRecord.requestType = DictTabInfo::AddTableFromDict;
    parseRecord.errorCode = 0;
    
    SimplePropertiesSectionReader r(tabInfoPtr, getSectionSegmentPool());
    
    handleTabInfoInit(r, &parseRecord);

    ndbrequire(parseRecord.errorCode == 0);
  }
  
  ndbrequire(!createTabPtr.isNull());

  SegmentedSectionPtr fragPtr;
  signal->getSection(fragPtr, CreateTabReq::FRAGMENTATION);

  createTabPtr.p->m_tabInfoPtrI = tabInfoPtr.i;
  createTabPtr.p->m_fragmentsPtrI = fragPtr.i;
  
  signal->header.m_noOfSections = 0;
  
  TableRecordPtr tabPtr;
  c_tableRecordPool.getPtr(tabPtr, tableId);
  tabPtr.p->packedSize = tabInfoPtr.sz;
  tabPtr.p->tableVersion = tableVersion;
  tabPtr.p->gciTableCreated = gci;

  SchemaFile::TableEntry tabEntry;
  tabEntry.m_tableVersion = tableVersion;
  tabEntry.m_tableType    = tabPtr.p->tableType;
  tabEntry.m_tableState   = SchemaFile::ADD_STARTED;
  tabEntry.m_gcp          = gci;
  tabEntry.m_noOfPages    = 
    DIV(tabInfoPtr.sz + ZPAGE_HEADER_SIZE, ZSIZE_OF_PAGES_IN_WORDS);
  
  Callback callback;
  callback.m_callbackData = createTabPtr.p->key;
  callback.m_callbackFunction = 
    safe_cast(&Dbdict::createTab_writeSchemaConf1);
  
  updateSchemaState(signal, tableId, &tabEntry, &callback);
}

void getSection(SegmentedSectionPtr & ptr, Uint32 i);

void
Dbdict::createTab_writeSchemaConf1(Signal* signal, 
				   Uint32 callbackData,
				   Uint32 returnCode){
  jam();

  CreateTableRecordPtr createTabPtr;  
  ndbrequire(c_opCreateTable.find(createTabPtr, callbackData));

  Callback callback;
  callback.m_callbackData = createTabPtr.p->key;
  callback.m_callbackFunction = 
    safe_cast(&Dbdict::createTab_writeTableConf);
  
  SegmentedSectionPtr tabInfoPtr;
  getSection(tabInfoPtr, createTabPtr.p->m_tabInfoPtrI);
  writeTableFile(signal, createTabPtr.p->m_tablePtrI, tabInfoPtr, &callback);

  createTabPtr.p->m_tabInfoPtrI = RNIL;
  signal->setSection(tabInfoPtr, 0);
  releaseSections(signal);
}

void
Dbdict::createTab_writeTableConf(Signal* signal, 
				 Uint32 callbackData,
				 Uint32 returnCode){
  jam();

  CreateTableRecordPtr createTabPtr;  
  ndbrequire(c_opCreateTable.find(createTabPtr, callbackData));

  SegmentedSectionPtr fragDataPtr;
  getSection(fragDataPtr, createTabPtr.p->m_fragmentsPtrI);
  
  Callback callback;
  callback.m_callbackData = callbackData;
  callback.m_callbackFunction = 
    safe_cast(&Dbdict::createTab_dihComplete);
  
  createTab_dih(signal, createTabPtr, fragDataPtr, &callback);
}

void
Dbdict::createTab_dih(Signal* signal, 
		      CreateTableRecordPtr createTabPtr, 
		      SegmentedSectionPtr fragDataPtr,
		      Callback * c){
  jam();
  
  createTabPtr.p->m_callback = * c;

  TableRecordPtr tabPtr;
  c_tableRecordPool.getPtr(tabPtr, createTabPtr.p->m_tablePtrI);
  
  DiAddTabReq * req = (DiAddTabReq*)signal->getDataPtrSend();
  req->connectPtr = createTabPtr.p->key;
  req->tableId = tabPtr.i;
  req->fragType = tabPtr.p->fragmentType;
  req->kValue = tabPtr.p->kValue;
  req->noOfReplicas = 0;
  req->storedTable = tabPtr.p->storedTable;
  req->tableType = tabPtr.p->tableType;
  req->schemaVersion = tabPtr.p->tableVersion;
  req->primaryTableId = tabPtr.p->primaryTableId;

  if(!fragDataPtr.isNull()){
    signal->setSection(fragDataPtr, DiAddTabReq::FRAGMENTATION);
  }

  sendSignal(DBDIH_REF, GSN_DIADDTABREQ, signal, 
	     DiAddTabReq::SignalLength, JBB);
}

static
void
calcLHbits(Uint32 * lhPageBits, Uint32 * lhDistrBits, 
	   Uint32 fid, Uint32 totalFragments) 
{
  Uint32 distrBits = 0;
  Uint32 pageBits = 0;
  
  Uint32 tmp = 1;
  while (tmp < totalFragments) {
    jam();
    tmp <<= 1;
    distrBits++;
  }//while
  if (tmp != totalFragments) {
    tmp >>= 1;
    if ((fid >= (totalFragments - tmp)) && (fid < (tmp - 1))) {
      distrBits--;
    }//if
  }//if
  * lhPageBits = pageBits;
  * lhDistrBits = distrBits;

}//calcLHbits()


void 
Dbdict::execADD_FRAGREQ(Signal* signal) {
  jamEntry();

  AddFragReq * const req = (AddFragReq*)signal->getDataPtr();
  
  Uint32 dihPtr = req->dihPtr;
  Uint32 senderData = req->senderData;
  Uint32 tableId = req->tableId;
  Uint32 fragId = req->fragmentId;
  Uint32 node = req->nodeId;
  Uint32 lcpNo = req->nextLCP;
  Uint32 fragCount = req->totalFragments;
  Uint32 requestInfo = req->requestInfo;
  Uint32 startGci = req->startGci;

  ndbrequire(node == getOwnNodeId());

  CreateTableRecordPtr createTabPtr;  
  ndbrequire(c_opCreateTable.find(createTabPtr, senderData));
  
  createTabPtr.p->m_dihAddFragPtr = dihPtr;
  
  TableRecordPtr tabPtr;
  c_tableRecordPool.getPtr(tabPtr, tableId);

#if 0
  tabPtr.p->gciTableCreated = (startGci > tabPtr.p->gciTableCreated ? startGci:
			       startGci > tabPtr.p->gciTableCreated);
#endif
  
  /**
   * Calc lh3PageBits
   */
  Uint32 lhDistrBits = 0;
  Uint32 lhPageBits = 0;
  ::calcLHbits(&lhPageBits, &lhDistrBits, fragId, fragCount);

  {  
    LqhFragReq* req = (LqhFragReq*)signal->getDataPtrSend();
    req->senderData = senderData;
    req->senderRef = reference();
    req->fragmentId = fragId;
    req->requestInfo = requestInfo;
    req->tableId = tableId;
    req->localKeyLength = tabPtr.p->localKeyLen;
    req->maxLoadFactor = tabPtr.p->maxLoadFactor;
    req->minLoadFactor = tabPtr.p->minLoadFactor;
    req->kValue = tabPtr.p->kValue;
    req->lh3DistrBits = 0; //lhDistrBits;
    req->lh3PageBits = 0; //lhPageBits;
    req->noOfAttributes = tabPtr.p->noOfAttributes;
    req->noOfNullAttributes = tabPtr.p->noOfNullBits;
    req->noOfPagesToPreAllocate = 0;
    req->schemaVersion = tabPtr.p->tableVersion;
    Uint32 keyLen = tabPtr.p->tupKeyLength;
    req->keyLength = keyLen; // wl-2066 no more "long keys"
    req->nextLCP = lcpNo;

    req->noOfKeyAttr = tabPtr.p->noOfPrimkey;
    req->noOfNewAttr = 0;
    // noOfCharsets passed to TUP in upper half
    req->noOfNewAttr |= (tabPtr.p->noOfCharsets << 16);
    req->checksumIndicator = 1;
    req->noOfAttributeGroups = 1;
    req->GCPIndicator = 0;
    req->startGci = startGci;
    req->tableType = tabPtr.p->tableType;
    req->primaryTableId = tabPtr.p->primaryTableId;
    sendSignal(DBLQH_REF, GSN_LQHFRAGREQ, signal, 
	       LqhFragReq::SignalLength, JBB);
  }
}

void
Dbdict::execLQHFRAGREF(Signal * signal){
  jamEntry();
  LqhFragRef * const ref = (LqhFragRef*)signal->getDataPtr();
 
  CreateTableRecordPtr createTabPtr;  
  ndbrequire(c_opCreateTable.find(createTabPtr, ref->senderData));
  
  createTabPtr.p->setErrorCode(ref->errorCode);
  
  {
    AddFragRef * const ref = (AddFragRef*)signal->getDataPtr();
    ref->dihPtr = createTabPtr.p->m_dihAddFragPtr;
    sendSignal(DBDIH_REF, GSN_ADD_FRAGREF, signal, 
	       AddFragRef::SignalLength, JBB);
  }
}

void
Dbdict::execLQHFRAGCONF(Signal * signal){
  jamEntry();
  LqhFragConf * const conf = (LqhFragConf*)signal->getDataPtr();

  CreateTableRecordPtr createTabPtr;  
  ndbrequire(c_opCreateTable.find(createTabPtr, conf->senderData));
  
  createTabPtr.p->m_lqhFragPtr = conf->lqhFragPtr;
  
  TableRecordPtr tabPtr;
  c_tableRecordPool.getPtr(tabPtr, createTabPtr.p->m_tablePtrI);
  sendLQHADDATTRREQ(signal, createTabPtr, tabPtr.p->firstAttribute);
}

void
Dbdict::sendLQHADDATTRREQ(Signal* signal,
			  CreateTableRecordPtr createTabPtr,
			  Uint32 attributePtrI){
  jam();
  TableRecordPtr tabPtr;
  c_tableRecordPool.getPtr(tabPtr, createTabPtr.p->m_tablePtrI);
  LqhAddAttrReq * const req = (LqhAddAttrReq*)signal->getDataPtrSend();
  Uint32 i = 0;
  for(i = 0; i<LqhAddAttrReq::MAX_ATTRIBUTES && attributePtrI != RNIL; i++){
    jam();
    AttributeRecordPtr attrPtr;
    c_attributeRecordPool.getPtr(attrPtr, attributePtrI);
    LqhAddAttrReq::Entry& entry = req->attributes[i];
    entry.attrId = attrPtr.p->attributeId;
    entry.attrDescriptor = attrPtr.p->attributeDescriptor;
    entry.extTypeInfo = 0;
    // charset number passed to TUP, TUX in upper half
    entry.extTypeInfo |= (attrPtr.p->extPrecision & ~0xFFFF);
    if (tabPtr.p->isIndex()) {
      Uint32 primaryAttrId;
      if (attrPtr.p->nextAttrInTable != RNIL) {
        getIndexAttr(tabPtr, attributePtrI, &primaryAttrId);
      } else {
        primaryAttrId = ZNIL;
        if (tabPtr.p->isOrderedIndex())
          entry.attrId = 0;     // attribute goes to TUP
      }
      entry.attrId |= (primaryAttrId << 16);
    }
    attributePtrI = attrPtr.p->nextAttrInTable;
  }
  req->lqhFragPtr = createTabPtr.p->m_lqhFragPtr;
  req->senderData = createTabPtr.p->key;
  req->senderAttrPtr = attributePtrI;
  req->noOfAttributes = i;
  
  sendSignal(DBLQH_REF, GSN_LQHADDATTREQ, signal, 
	     LqhAddAttrReq::HeaderLength + LqhAddAttrReq::EntryLength * i, JBB);
}

void
Dbdict::execLQHADDATTREF(Signal * signal){
  jamEntry();
  LqhAddAttrRef * const ref = (LqhAddAttrRef*)signal->getDataPtr();

  CreateTableRecordPtr createTabPtr;  
  ndbrequire(c_opCreateTable.find(createTabPtr, ref->senderData));
  
  createTabPtr.p->setErrorCode(ref->errorCode);
  
  {
    AddFragRef * const ref = (AddFragRef*)signal->getDataPtr();
    ref->dihPtr = createTabPtr.p->m_dihAddFragPtr;
    sendSignal(DBDIH_REF, GSN_ADD_FRAGREF, signal, 
	       AddFragRef::SignalLength, JBB);
  }
  
}

void
Dbdict::execLQHADDATTCONF(Signal * signal){
  jamEntry();
  LqhAddAttrConf * const conf = (LqhAddAttrConf*)signal->getDataPtr();

  CreateTableRecordPtr createTabPtr;
  ndbrequire(c_opCreateTable.find(createTabPtr, conf->senderData));
  
  const Uint32 fragId = conf->fragId;
  const Uint32 nextAttrPtr = conf->senderAttrPtr;
  if(nextAttrPtr != RNIL){
    jam();
    sendLQHADDATTRREQ(signal, createTabPtr, nextAttrPtr);
    return;
  }

  {
    AddFragConf * const conf = (AddFragConf*)signal->getDataPtr();
    conf->dihPtr = createTabPtr.p->m_dihAddFragPtr;
    conf->fragId = fragId;
    sendSignal(DBDIH_REF, GSN_ADD_FRAGCONF, signal, 
	       AddFragConf::SignalLength, JBB);
  }
}

void
Dbdict::execDIADDTABREF(Signal* signal){
  jam();
  
  DiAddTabRef * const ref = (DiAddTabRef*)signal->getDataPtr();
  
  CreateTableRecordPtr createTabPtr;  
  ndbrequire(c_opCreateTable.find(createTabPtr, ref->senderData));
  
  createTabPtr.p->setErrorCode(ref->errorCode);  
  execute(signal, createTabPtr.p->m_callback, 0);
}

void
Dbdict::execDIADDTABCONF(Signal* signal){
  jam();
  
  DiAddTabConf * const conf = (DiAddTabConf*)signal->getDataPtr();
  
  CreateTableRecordPtr createTabPtr;  
  ndbrequire(c_opCreateTable.find(createTabPtr, conf->senderData));

  signal->theData[0] = createTabPtr.p->key;
  signal->theData[1] = reference();
  signal->theData[2] = createTabPtr.p->m_tablePtrI;

  if(createTabPtr.p->m_dihAddFragPtr != RNIL){
    jam();

    /**
     * We did perform at least one LQHFRAGREQ
     */
    sendSignal(DBLQH_REF, GSN_TAB_COMMITREQ, signal, 3, JBB);
    return;
  } else {
    /**
     * No local fragment (i.e. no LQHFRAGREQ)
     */
    execute(signal, createTabPtr.p->m_callback, 0);
    return;
    //sendSignal(DBDIH_REF, GSN_TAB_COMMITREQ, signal, 3, JBB);
  }
}

void 
Dbdict::execTAB_COMMITREF(Signal* signal) {
  jamEntry();
  ndbrequire(false);
}//execTAB_COMMITREF()

void
Dbdict::execTAB_COMMITCONF(Signal* signal){
  jamEntry();

  CreateTableRecordPtr createTabPtr;  
  ndbrequire(c_opCreateTable.find(createTabPtr, signal->theData[0]));
  
  if(refToBlock(signal->getSendersBlockRef()) == DBLQH){

    execute(signal, createTabPtr.p->m_callback, 0);
    return;
  }

  if(refToBlock(signal->getSendersBlockRef()) == DBDIH){
    TableRecordPtr tabPtr;
    c_tableRecordPool.getPtr(tabPtr, createTabPtr.p->m_tablePtrI);
    
    signal->theData[0] = tabPtr.i;
    signal->theData[1] = tabPtr.p->tableVersion;
    signal->theData[2] = (Uint32)tabPtr.p->storedTable;     
    signal->theData[3] = reference();
    signal->theData[4] = (Uint32)tabPtr.p->tableType;
    signal->theData[5] = createTabPtr.p->key;
    signal->theData[6] = (Uint32)tabPtr.p->noOfPrimkey;

    Uint32 buf[2 * MAX_ATTRIBUTES_IN_INDEX];
    Uint32 sz = 0;
    Uint32 tAttr = tabPtr.p->firstAttribute;
    while (tAttr != RNIL) {
      jam();
      AttributeRecord* aRec = c_attributeRecordPool.getPtr(tAttr);
      if (aRec->tupleKey) {
        buf[sz++] = aRec->attributeDescriptor;
        buf[sz++] = (aRec->extPrecision >> 16); // charset number
      }
      tAttr = aRec->nextAttrInTable;
    }
    ndbrequire((int)sz == 2 * tabPtr.p->noOfPrimkey);

    LinearSectionPtr lsPtr[3];
    lsPtr[0].p = buf;
    lsPtr[0].sz = sz;
    // note: ACC does not reply
    sendSignal(DBACC_REF, GSN_TC_SCHVERREQ, signal, 7, JBB, lsPtr, 1);
    sendSignal(DBTC_REF, GSN_TC_SCHVERREQ, signal, 7, JBB, lsPtr, 1);
    return;
  }

  ndbrequire(false);
}

void
Dbdict::createTab_dihComplete(Signal* signal, 
			      Uint32 callbackData,
			      Uint32 returnCode){
  jam();

  CreateTableRecordPtr createTabPtr;  
  ndbrequire(c_opCreateTable.find(createTabPtr, callbackData));

  //@todo check for master failed
  
  if(createTabPtr.p->m_errorCode == 0){
    jam();

    CreateTabConf * const conf = (CreateTabConf*)signal->getDataPtr();
    conf->senderRef = reference();
    conf->senderData = createTabPtr.p->key;
    sendSignal(createTabPtr.p->m_coordinatorRef, GSN_CREATE_TAB_CONF,
	       signal, CreateTabConf::SignalLength, JBB);
    return;
  }

  CreateTabRef * const ref = (CreateTabRef*)signal->getDataPtr();
  ref->senderRef = reference();
  ref->senderData = createTabPtr.p->key;
  ref->errorCode = createTabPtr.p->m_errorCode;
  ref->errorLine = 0;
  ref->errorKey = 0;
  ref->errorStatus = 0;

  sendSignal(createTabPtr.p->m_coordinatorRef, GSN_CREATE_TAB_REF,
	     signal, CreateTabRef::SignalLength, JBB);
}

void
Dbdict::createTab_commit(Signal * signal, CreateTabReq * req){
  jam();
  
  CreateTableRecordPtr createTabPtr;  
  ndbrequire(c_opCreateTable.find(createTabPtr, req->senderData));

  TableRecordPtr tabPtr;
  c_tableRecordPool.getPtr(tabPtr, createTabPtr.p->m_tablePtrI);
  
  SchemaFile::TableEntry tabEntry;
  tabEntry.m_tableVersion = tabPtr.p->tableVersion;
  tabEntry.m_tableType    = tabPtr.p->tableType;
  tabEntry.m_tableState   = SchemaFile::TABLE_ADD_COMMITTED;
  tabEntry.m_gcp          = tabPtr.p->gciTableCreated;
  tabEntry.m_noOfPages    = 
    DIV(tabPtr.p->packedSize + ZPAGE_HEADER_SIZE, ZSIZE_OF_PAGES_IN_WORDS);
  
  Callback callback;
  callback.m_callbackData = createTabPtr.p->key;
  callback.m_callbackFunction = 
    safe_cast(&Dbdict::createTab_writeSchemaConf2);
  
  updateSchemaState(signal, tabPtr.i, &tabEntry, &callback);
}

void
Dbdict::createTab_writeSchemaConf2(Signal* signal, 
				   Uint32 callbackData,
				   Uint32 returnCode){
  jam();
  
  CreateTableRecordPtr createTabPtr;  
  ndbrequire(c_opCreateTable.find(createTabPtr, callbackData));
  
  Callback c;
  c.m_callbackData = callbackData;
  c.m_callbackFunction = safe_cast(&Dbdict::createTab_alterComplete);
  alterTab_activate(signal, createTabPtr, &c);
}

void
Dbdict::createTab_alterComplete(Signal* signal, 
				Uint32 callbackData,
				Uint32 returnCode){
  jam();

  CreateTableRecordPtr createTabPtr;  
  ndbrequire(c_opCreateTable.find(createTabPtr, callbackData));
  
  TableRecordPtr tabPtr;
  c_tableRecordPool.getPtr(tabPtr, createTabPtr.p->m_tablePtrI);
  tabPtr.p->tabState = TableRecord::DEFINED;
  
  //@todo check error
  //@todo check master failed
  
  CreateTabConf * const conf = (CreateTabConf*)signal->getDataPtr();
  conf->senderRef = reference();
  conf->senderData = createTabPtr.p->key;
  sendSignal(createTabPtr.p->m_coordinatorRef, GSN_CREATE_TAB_CONF,
	     signal, CreateTabConf::SignalLength, JBB);

  if(createTabPtr.p->m_coordinatorRef != reference()){
    jam();
    c_opCreateTable.release(createTabPtr);
  }
}

void
Dbdict::createTab_drop(Signal* signal, CreateTabReq * req){
  jam();

  const Uint32 key = req->senderData;

  CreateTableRecordPtr createTabPtr;  
  ndbrequire(c_opCreateTable.find(createTabPtr, key));
  
  TableRecordPtr tabPtr;
  c_tableRecordPool.getPtr(tabPtr, createTabPtr.p->m_tablePtrI);
  tabPtr.p->tabState = TableRecord::DROPPING;

  DropTableRecordPtr dropTabPtr;  
  ndbrequire(c_opDropTable.seize(dropTabPtr));
  
  dropTabPtr.p->key = key;
  c_opDropTable.add(dropTabPtr);
  
  dropTabPtr.p->m_errorCode = 0;
  dropTabPtr.p->m_request.tableId = createTabPtr.p->m_tablePtrI;
  dropTabPtr.p->m_requestType = DropTabReq::CreateTabDrop;
  dropTabPtr.p->m_coordinatorRef = createTabPtr.p->m_coordinatorRef;
  dropTabPtr.p->m_participantData.m_gsn = GSN_DROP_TAB_REQ;
  
  dropTabPtr.p->m_participantData.m_block = 0;
  dropTabPtr.p->m_participantData.m_callback.m_callbackData = req->senderData;
  dropTabPtr.p->m_participantData.m_callback.m_callbackFunction = 
    safe_cast(&Dbdict::createTab_dropComplete);
  dropTab_nextStep(signal, dropTabPtr);  
}

void
Dbdict::createTab_dropComplete(Signal* signal, 
			       Uint32 callbackData,
			       Uint32 returnCode){
  jam();

  CreateTableRecordPtr createTabPtr;  
  ndbrequire(c_opCreateTable.find(createTabPtr, callbackData));
  
  DropTableRecordPtr dropTabPtr;
  ndbrequire(c_opDropTable.find(dropTabPtr, callbackData));

  TableRecordPtr tabPtr;
  c_tableRecordPool.getPtr(tabPtr, createTabPtr.p->m_tablePtrI);
  
  releaseTableObject(tabPtr.i);
  PageRecordPtr pagePtr;
  c_pageRecordArray.getPtr(pagePtr, c_schemaRecord.schemaPage);

  SchemaFile::TableEntry * tableEntry = getTableEntry(pagePtr.p, tabPtr.i);
  tableEntry->m_tableState = SchemaFile::DROP_TABLE_COMMITTED;
  
  //@todo check error
  //@todo check master failed
  
  CreateTabConf * const conf = (CreateTabConf*)signal->getDataPtr();
  conf->senderRef = reference();
  conf->senderData = createTabPtr.p->key;
  sendSignal(createTabPtr.p->m_coordinatorRef, GSN_CREATE_TAB_CONF,
	     signal, CreateTabConf::SignalLength, JBB);

  if(createTabPtr.p->m_coordinatorRef != reference()){
    jam();
    c_opCreateTable.release(createTabPtr);
  }

  c_opDropTable.release(dropTabPtr);
}

void
Dbdict::alterTab_activate(Signal* signal, CreateTableRecordPtr createTabPtr,
			  Callback * c){

  createTabPtr.p->m_callback = * c;
  
  signal->theData[0] = createTabPtr.p->key;
  signal->theData[1] = reference();
  signal->theData[2] = createTabPtr.p->m_tablePtrI;
  sendSignal(DBDIH_REF, GSN_TAB_COMMITREQ, signal, 3, JBB);
}

void
Dbdict::execTC_SCHVERCONF(Signal* signal){
  jamEntry();

  CreateTableRecordPtr createTabPtr;  
  ndbrequire(c_opCreateTable.find(createTabPtr, signal->theData[1]));

  execute(signal, createTabPtr.p->m_callback, 0);
}

#define tabRequire(cond, error) \
  if (!(cond)) { \
    jam();    \
    parseP->errorCode = error; parseP->errorLine = __LINE__; \
    parseP->errorKey = it.getKey(); \
    return;   \
  }//if

// handleAddTableFailure(signal, __LINE__, allocatedTable);

void Dbdict::handleTabInfoInit(SimpleProperties::Reader & it,
			       ParseDictTabInfoRecord * parseP,
			       bool checkExist) 
{
/* ---------------------------------------------------------------- */
// We always start by handling table name since this must be the first
// item in the list. Through the table name we can derive if it is a
// correct name, a new name or an already existing table.
/* ---------------------------------------------------------------- */

  it.first();

  SimpleProperties::UnpackStatus status;
  DictTabInfo::Table tableDesc; tableDesc.init();
  status = SimpleProperties::unpack(it, &tableDesc, 
				    DictTabInfo::TableMapping, 
				    DictTabInfo::TableMappingSize, 
				    true, true);
  
  if(status != SimpleProperties::Break){
    parseP->errorCode = CreateTableRef::InvalidFormat;
    parseP->status    = status;
    parseP->errorKey  = it.getKey();
    parseP->errorLine = __LINE__;
    return;
  }

  if(parseP->requestType == DictTabInfo::AlterTableFromAPI)
  {  
    ndbrequire(!checkExist);
  }
  if(!checkExist)
  {
    ndbrequire(parseP->requestType == DictTabInfo::AlterTableFromAPI);
  }
  
  /* ---------------------------------------------------------------- */
  // Verify that table name is an allowed table name.
  // TODO
  /* ---------------------------------------------------------------- */
  const Uint32 tableNameLength = strlen(tableDesc.TableName) + 1;

  TableRecord keyRecord;
  tabRequire(tableNameLength <= sizeof(keyRecord.tableName),
	     CreateTableRef::TableNameTooLong);
  strcpy(keyRecord.tableName, tableDesc.TableName);
  
  TableRecordPtr tablePtr;
  c_tableRecordHash.find(tablePtr, keyRecord);
  
  if (checkExist){
    jam();
    /* ---------------------------------------------------------------- */
    // Check if table already existed.
    /* ---------------------------------------------------------------- */
    tabRequire(tablePtr.i == RNIL, CreateTableRef::TableAlreadyExist);
  }

  switch (parseP->requestType) {
  case DictTabInfo::CreateTableFromAPI: {
    jam();
  }
  case DictTabInfo::AlterTableFromAPI:{
    jam();
    tablePtr.i = getFreeTableRecord(tableDesc.PrimaryTableId);
    /* ---------------------------------------------------------------- */
    // Check if no free tables existed.
    /* ---------------------------------------------------------------- */
    tabRequire(tablePtr.i != RNIL, CreateTableRef::NoMoreTableRecords);
    
    c_tableRecordPool.getPtr(tablePtr);
    break;
  }
  case DictTabInfo::AddTableFromDict:
  case DictTabInfo::ReadTableFromDiskSR:
  case DictTabInfo::GetTabInfoConf:
  {
/* ---------------------------------------------------------------- */
// Get table id and check that table doesn't already exist
/* ---------------------------------------------------------------- */
    tablePtr.i = tableDesc.TableId;
    
    if (parseP->requestType == DictTabInfo::ReadTableFromDiskSR) {
      ndbrequire(tablePtr.i == c_restartRecord.activeTable);
    }//if
    if (parseP->requestType == DictTabInfo::GetTabInfoConf) {
      ndbrequire(tablePtr.i == c_restartRecord.activeTable);
    }//if
    
    c_tableRecordPool.getPtr(tablePtr);
    ndbrequire(tablePtr.p->tabState == TableRecord::NOT_DEFINED);
    
    //Uint32 oldTableVersion = tablePtr.p->tableVersion;
    initialiseTableRecord(tablePtr);
    if (parseP->requestType == DictTabInfo::AddTableFromDict) {
      jam();
      tablePtr.p->tabState = TableRecord::DEFINING;
    }//if
#ifdef HAVE_TABLE_REORG
/* ---------------------------------------------------------------- */
// Get id of second table id and check that table doesn't already exist
// and set up links between first and second table.
/* ---------------------------------------------------------------- */
    TableRecordPtr secondTablePtr;
    secondTablePtr.i = tableDesc.SecondTableId;
    c_tableRecordPool.getPtr(secondTablePtr);
    ndbrequire(secondTablePtr.p->tabState == TableRecord::NOT_DEFINED);
    
    initialiseTableRecord(secondTablePtr);
    secondTablePtr.p->tabState = TableRecord::REORG_TABLE_PREPARED;
    secondTablePtr.p->secondTable = tablePtr.i;
    tablePtr.p->secondTable = secondTablePtr.i;
#endif
/* ---------------------------------------------------------------- */
// Set table version
/* ---------------------------------------------------------------- */
    Uint32 tableVersion = tableDesc.TableVersion;
    tablePtr.p->tableVersion = tableVersion;
    
    break;
  }
  default:
    ndbrequire(false);
    break;
  }//switch
  parseP->tablePtr = tablePtr;
  
  strcpy(tablePtr.p->tableName, keyRecord.tableName);  
  if (parseP->requestType != DictTabInfo::AlterTableFromAPI) {
    jam();
#ifdef VM_TRACE
    ndbout_c("Dbdict: name=%s,id=%u", tablePtr.p->tableName, tablePtr.i);
    TableRecordPtr tmp;
    ndbrequire(!c_tableRecordHash.find(tmp, * tablePtr.p));
#endif
    c_tableRecordHash.add(tablePtr);
  }
  
  //tablePtr.p->noOfPrimkey = tableDesc.NoOfKeyAttr;
  //tablePtr.p->noOfNullAttr = tableDesc.NoOfNullable;
  //tablePtr.p->tupKeyLength = tableDesc.KeyLength;
  tablePtr.p->noOfAttributes = tableDesc.NoOfAttributes;
  tablePtr.p->storedTable = tableDesc.TableLoggedFlag;
  tablePtr.p->minLoadFactor = tableDesc.MinLoadFactor;
  tablePtr.p->maxLoadFactor = tableDesc.MaxLoadFactor;
  tablePtr.p->fragmentType = (DictTabInfo::FragmentType)tableDesc.FragmentType;
  tablePtr.p->tableType = (DictTabInfo::TableType)tableDesc.TableType;
  tablePtr.p->kValue = tableDesc.TableKValue;
  tablePtr.p->fragmentCount = tableDesc.FragmentCount;

  tablePtr.p->frmLen = tableDesc.FrmLen;
  memcpy(tablePtr.p->frmData, tableDesc.FrmData, tableDesc.FrmLen);  

  if(tableDesc.PrimaryTableId != RNIL) {
    
    tablePtr.p->primaryTableId = tableDesc.PrimaryTableId;
    tablePtr.p->indexState = (TableRecord::IndexState)tableDesc.IndexState;
    tablePtr.p->insertTriggerId = tableDesc.InsertTriggerId;
    tablePtr.p->updateTriggerId = tableDesc.UpdateTriggerId;
    tablePtr.p->deleteTriggerId = tableDesc.DeleteTriggerId;
    tablePtr.p->customTriggerId = tableDesc.CustomTriggerId;
  } else {
    tablePtr.p->primaryTableId = RNIL;
    tablePtr.p->indexState = TableRecord::IS_UNDEFINED;
    tablePtr.p->insertTriggerId = RNIL;
    tablePtr.p->updateTriggerId = RNIL;
    tablePtr.p->deleteTriggerId = RNIL;
    tablePtr.p->customTriggerId = RNIL;
  }
  tablePtr.p->buildTriggerId = RNIL;
  tablePtr.p->indexLocal = 0;
  
  handleTabInfo(it, parseP);

  if(parseP->errorCode != 0)
  {
    /**
     * Release table
     */
    releaseTableObject(tablePtr.i, checkExist);
  }
}//handleTabInfoInit()

void Dbdict::handleTabInfo(SimpleProperties::Reader & it,
			   ParseDictTabInfoRecord * parseP)
{
  TableRecordPtr tablePtr = parseP->tablePtr;
  
  SimpleProperties::UnpackStatus status;
  
  Uint32 keyCount = 0;
  Uint32 keyLength = 0;
  Uint32 attrCount = tablePtr.p->noOfAttributes;
  Uint32 nullCount = 0;
  Uint32 nullBits = 0;
  Uint32 noOfCharsets = 0;
  Uint16 charsets[128];
  Uint32 recordLength = 0;
  AttributeRecordPtr attrPtr;
  c_attributeRecordHash.removeAll();
  
  for(Uint32 i = 0; i<attrCount; i++){
    /**
     * Attribute Name
     */
    DictTabInfo::Attribute attrDesc; attrDesc.init();
    status = SimpleProperties::unpack(it, &attrDesc, 
				      DictTabInfo::AttributeMapping, 
				      DictTabInfo::AttributeMappingSize, 
				      true, true);
    if(status != SimpleProperties::Break){
      parseP->errorCode = CreateTableRef::InvalidFormat;
      parseP->status    = status;
      parseP->errorKey  = it.getKey();
      parseP->errorLine = __LINE__;
      return;
    }

    /**
     * Check that attribute is not defined twice
     */
    AttributeRecord tmpAttr;
    {
      strcpy(tmpAttr.attributeName, attrDesc.AttributeName); 
      
      AttributeRecordPtr attrPtr;
      c_attributeRecordHash.find(attrPtr, tmpAttr);
      
      if(attrPtr.i != RNIL){
	parseP->errorCode = CreateTableRef::AttributeNameTwice;
	return;
      }
    }
    
    if(!getNewAttributeRecord(tablePtr, attrPtr)){
      jam();
      parseP->errorCode = CreateTableRef::NoMoreAttributeRecords;
      return;
    }
    
    /**
     * TmpAttrib to Attribute mapping
     */
    strcpy(attrPtr.p->attributeName, attrDesc.AttributeName);
    attrPtr.p->attributeId = attrDesc.AttributeId;
    attrPtr.p->tupleKey = (keyCount + 1) * attrDesc.AttributeKeyFlag;

    attrPtr.p->extPrecision = attrDesc.AttributeExtPrecision;
    attrPtr.p->extScale = attrDesc.AttributeExtScale;
    attrPtr.p->extLength = attrDesc.AttributeExtLength;
    // charset in upper half of precision
    unsigned csNumber = (attrPtr.p->extPrecision >> 16);
    if (csNumber != 0) {
      /*
       * A new charset is first accessed here on this node.
       * TODO use separate thread (e.g. via NDBFS) if need to load from file
       */
      CHARSET_INFO* cs = get_charset(csNumber, MYF(0));
      if (cs == NULL) {
        parseP->errorCode = CreateTableRef::InvalidCharset;
        parseP->errorLine = __LINE__;
        return;
      }
      // XXX should be done somewhere in mysql
      all_charsets[cs->number] = cs;
      unsigned i = 0;
      while (i < noOfCharsets) {
        if (charsets[i] == csNumber)
          break;
        i++;
      }
      if (i == noOfCharsets) {
        noOfCharsets++;
        if (noOfCharsets > sizeof(charsets)/sizeof(charsets[0])) {
          parseP->errorCode = CreateTableRef::InvalidFormat;
          parseP->errorLine = __LINE__;
          return;
        }
        charsets[i] = csNumber;
      }
    }

    // compute attribute size and array size
    bool translateOk = attrDesc.translateExtType();
    tabRequire(translateOk, CreateTableRef::Inconsistency);

    if(attrDesc.AttributeArraySize > 65535){
      parseP->errorCode = CreateTableRef::ArraySizeTooBig;
      parseP->status    = status;
      parseP->errorKey  = it.getKey();
      parseP->errorLine = __LINE__;
      return;
    }
    
    Uint32 desc = 0;
    AttributeDescriptor::setType(desc, attrDesc.AttributeExtType);
    AttributeDescriptor::setSize(desc, attrDesc.AttributeSize);
    AttributeDescriptor::setArray(desc, attrDesc.AttributeArraySize);
    AttributeDescriptor::setNullable(desc, attrDesc.AttributeNullableFlag);
    AttributeDescriptor::setDKey(desc, attrDesc.AttributeDKey);
    AttributeDescriptor::setPrimaryKey(desc, attrDesc.AttributeKeyFlag);
    attrPtr.p->attributeDescriptor = desc;
    attrPtr.p->autoIncrement = attrDesc.AttributeAutoIncrement;
    strcpy(attrPtr.p->defaultValue, attrDesc.AttributeDefaultValue);
    
    tabRequire(attrDesc.AttributeId == i, CreateTableRef::InvalidFormat);
    
    attrCount ++;
    keyCount += attrDesc.AttributeKeyFlag;
    nullCount += attrDesc.AttributeNullableFlag;
    
    const Uint32 aSz = (1 << attrDesc.AttributeSize);
    Uint32 sz;
    if(aSz != 1)
    {
      sz = ((aSz * attrDesc.AttributeArraySize) + 31) >> 5;
    }    
    else
    {
      sz = 0;
      nullBits += attrDesc.AttributeArraySize;      
    }
    
    if(attrDesc.AttributeArraySize == 0)
    {
      parseP->errorCode = CreateTableRef::InvalidArraySize;
      parseP->status    = status;
      parseP->errorKey  = it.getKey();
      parseP->errorLine = __LINE__;
      return;
    }
    
    recordLength += sz;
    if(attrDesc.AttributeKeyFlag){
      keyLength += sz;

      if(attrDesc.AttributeNullableFlag){
	parseP->errorCode = CreateTableRef::NullablePrimaryKey;
	parseP->status    = status;
	parseP->errorKey  = it.getKey();
	parseP->errorLine = __LINE__;
	return;
      }
    }
    
    if (parseP->requestType != DictTabInfo::AlterTableFromAPI)
      c_attributeRecordHash.add(attrPtr);
    
    if(!it.next())
      break;
    
    if(it.getKey() != DictTabInfo::AttributeName)
      break;
  }//while
  
  tablePtr.p->noOfPrimkey = keyCount;
  tablePtr.p->noOfNullAttr = nullCount;
  tablePtr.p->noOfCharsets = noOfCharsets;
  tablePtr.p->tupKeyLength = keyLength;
  tablePtr.p->noOfNullBits = nullCount + nullBits;

  tabRequire(recordLength<= MAX_TUPLE_SIZE_IN_WORDS, 
	     CreateTableRef::RecordTooBig);
  tabRequire(keyLength <= MAX_KEY_SIZE_IN_WORDS, 
	     CreateTableRef::InvalidPrimaryKeySize);
  tabRequire(keyLength > 0, 
	     CreateTableRef::InvalidPrimaryKeySize);
  
}//handleTabInfo()


/* ---------------------------------------------------------------- */
// DICTTABCONF is sent when participants have received all DICTTABINFO
// and successfully handled it.
// Also sent to self (DICT master) when index table creation ready.
/* ---------------------------------------------------------------- */
void Dbdict::execCREATE_TABLE_CONF(Signal* signal) 
{
  jamEntry();
  ndbrequire(signal->getNoOfSections() == 0);

  CreateTableConf * const conf = (CreateTableConf *)signal->getDataPtr();
  // assume part of create index operation
  OpCreateIndexPtr opPtr;
  c_opCreateIndex.find(opPtr, conf->senderData);
  ndbrequire(! opPtr.isNull());
  opPtr.p->m_request.setIndexId(conf->tableId);
  opPtr.p->m_request.setIndexVersion(conf->tableVersion);
  createIndex_fromCreateTable(signal, opPtr);
}//execCREATE_TABLE_CONF()

void Dbdict::execCREATE_TABLE_REF(Signal* signal) 
{
  jamEntry();

  CreateTableRef * const ref = (CreateTableRef *)signal->getDataPtr();
  // assume part of create index operation
  OpCreateIndexPtr opPtr;
  c_opCreateIndex.find(opPtr, ref->senderData);
  ndbrequire(! opPtr.isNull());
  opPtr.p->setError(ref);
  createIndex_fromCreateTable(signal, opPtr);
}//execCREATE_TABLE_REF()

/* ---------------------------------------------------------------- */
// New global checkpoint created.
/* ---------------------------------------------------------------- */
void Dbdict::execWAIT_GCP_CONF(Signal* signal) 
{
#if 0
  TableRecordPtr tablePtr;
  jamEntry();
  WaitGCPConf* const conf = (WaitGCPConf*)&signal->theData[0];
  c_tableRecordPool.getPtr(tablePtr, c_connRecord.connTableId);
  tablePtr.p->gciTableCreated = conf->gcp;
  sendUpdateSchemaState(signal,
                        tablePtr.i,
                        SchemaFile::TABLE_ADD_COMMITTED,
                        c_connRecord.noOfPagesForTable,
                        conf->gcp);
#endif
}//execWAIT_GCP_CONF()

/* ---------------------------------------------------------------- */
// Refused new global checkpoint.
/* ---------------------------------------------------------------- */
void Dbdict::execWAIT_GCP_REF(Signal* signal) 
{
  jamEntry();
  WaitGCPRef* const ref = (WaitGCPRef*)&signal->theData[0];
/* ---------------------------------------------------------------- */
// Error Handling code needed
/* ---------------------------------------------------------------- */
  progError(ref->errorCode, 0);
}//execWAIT_GCP_REF()


/* **************************************************************** */
/* ---------------------------------------------------------------- */
/* MODULE:          DROP TABLE                 -------------------- */
/* ---------------------------------------------------------------- */
/*                                                                  */
/* This module contains the code used to drop a table.              */
/* ---------------------------------------------------------------- */
/* **************************************************************** */
void
Dbdict::execDROP_TABLE_REQ(Signal* signal){
  jamEntry();
  DropTableReq* req = (DropTableReq*)signal->getDataPtr();

  TableRecordPtr tablePtr;
  c_tableRecordPool.getPtr(tablePtr, req->tableId, false);
  if(tablePtr.isNull()){
    jam();
    dropTableRef(signal, req, DropTableRef::NoSuchTable);
    return;
  }

  if(getOwnNodeId() != c_masterNodeId){
    jam();
    dropTableRef(signal, req, DropTableRef::NotMaster);
    return;
  }

  if(c_blockState != BS_IDLE){
    jam();
    dropTableRef(signal, req, DropTableRef::Busy);
    return;
  }
  
  const TableRecord::TabState tabState = tablePtr.p->tabState;
  bool ok = false;
  switch(tabState){
  case TableRecord::NOT_DEFINED:
  case TableRecord::REORG_TABLE_PREPARED:
  case TableRecord::DEFINING:
  case TableRecord::CHECKED:
    jam();
    dropTableRef(signal, req, DropTableRef::NoSuchTable);
    return;
  case TableRecord::DEFINED:
    ok = true;
    jam();
    break;
  case TableRecord::PREPARE_DROPPING:
  case TableRecord::DROPPING:
    jam();
    dropTableRef(signal, req, DropTableRef::DropInProgress);
    return;
  }
  ndbrequire(ok);

  if(tablePtr.p->tableVersion != req->tableVersion){
    jam();
    dropTableRef(signal, req, DropTableRef::InvalidTableVersion);
    return;
  }

  /**
   * Seems ok
   */
  DropTableRecordPtr dropTabPtr;
  c_opDropTable.seize(dropTabPtr);
  
  if(dropTabPtr.isNull()){
    jam();
    dropTableRef(signal, req, DropTableRef::NoDropTableRecordAvailable);
    return;
  }

  c_blockState = BS_BUSY;
  
  dropTabPtr.p->key = ++c_opRecordSequence;
  c_opDropTable.add(dropTabPtr);

  tablePtr.p->tabState = TableRecord::PREPARE_DROPPING;

  dropTabPtr.p->m_request = * req;
  dropTabPtr.p->m_errorCode = 0;
  dropTabPtr.p->m_requestType = DropTabReq::OnlineDropTab;
  dropTabPtr.p->m_coordinatorRef = reference();
  dropTabPtr.p->m_coordinatorData.m_gsn = GSN_PREP_DROP_TAB_REQ;
  dropTabPtr.p->m_coordinatorData.m_block = 0;
  prepDropTab_nextStep(signal, dropTabPtr);
}

void
Dbdict::dropTableRef(Signal * signal, 
		     DropTableReq * req, DropTableRef::ErrorCode errCode){

  Uint32 tableId = req->tableId;
  Uint32 tabVersion = req->tableVersion;
  Uint32 senderData = req->senderData;
  Uint32 senderRef = req->senderRef;
  
  DropTableRef * ref = (DropTableRef*)signal->getDataPtrSend();
  ref->tableId = tableId;
  ref->tableVersion = tabVersion;
  ref->senderData = senderData;
  ref->senderRef = reference();
  ref->errorCode = errCode;
  ref->masterNodeId = c_masterNodeId;
  sendSignal(senderRef, GSN_DROP_TABLE_REF, signal, 
	     DropTableRef::SignalLength, JBB);
}

void
Dbdict::prepDropTab_nextStep(Signal* signal, DropTableRecordPtr dropTabPtr){
  
  /**
   * No errors currently allowed
   */
  ndbrequire(dropTabPtr.p->m_errorCode == 0);

  Uint32 block = 0;
  switch(dropTabPtr.p->m_coordinatorData.m_block){
  case 0:
    jam();
    block = dropTabPtr.p->m_coordinatorData.m_block = DBDICT;
    break;
  case DBDICT:
    jam();
    block = dropTabPtr.p->m_coordinatorData.m_block = DBLQH;
    break;
  case DBLQH:
    jam();
    block = dropTabPtr.p->m_coordinatorData.m_block = DBTC;
    break;
  case DBTC:
    jam();
    block = dropTabPtr.p->m_coordinatorData.m_block = DBDIH;
    break;
  case DBDIH:
    jam();
    prepDropTab_complete(signal, dropTabPtr);
    return;
  default:
    ndbrequire(false);
  }

  PrepDropTabReq * prep = (PrepDropTabReq*)signal->getDataPtrSend();
  prep->senderRef = reference();
  prep->senderData = dropTabPtr.p->key;
  prep->tableId = dropTabPtr.p->m_request.tableId;
  prep->requestType = dropTabPtr.p->m_requestType;
  
  dropTabPtr.p->m_coordinatorData.m_signalCounter = c_aliveNodes;
  NodeReceiverGroup rg(block, c_aliveNodes);
  sendSignal(rg, GSN_PREP_DROP_TAB_REQ, signal, 
	     PrepDropTabReq::SignalLength, JBB);
  
#if 0  
  for (Uint32 i = 1; i < MAX_NDB_NODES; i++){
    if(c_aliveNodes.get(i)){
      jam();
      BlockReference ref = numberToRef(block, i);
      
      dropTabPtr.p->m_coordinatorData.m_signalCounter.setWaitingFor(i);
    }
  }
#endif
}

void
Dbdict::execPREP_DROP_TAB_CONF(Signal * signal){
  jamEntry();

  PrepDropTabConf * prep = (PrepDropTabConf*)signal->getDataPtr();

  DropTableRecordPtr dropTabPtr;  
  ndbrequire(c_opDropTable.find(dropTabPtr, prep->senderData));
  
  ndbrequire(dropTabPtr.p->m_coordinatorRef == reference());
  ndbrequire(dropTabPtr.p->m_request.tableId == prep->tableId);
  ndbrequire(dropTabPtr.p->m_coordinatorData.m_gsn == GSN_PREP_DROP_TAB_REQ);
  
  Uint32 nodeId = refToNode(prep->senderRef);
  dropTabPtr.p->m_coordinatorData.m_signalCounter.clearWaitingFor(nodeId);
  
  if(!dropTabPtr.p->m_coordinatorData.m_signalCounter.done()){
    jam();
    return;
  }
  prepDropTab_nextStep(signal, dropTabPtr);
}

void
Dbdict::execPREP_DROP_TAB_REF(Signal* signal){
  jamEntry();

  PrepDropTabRef * prep = (PrepDropTabRef*)signal->getDataPtr();

  DropTableRecordPtr dropTabPtr;  
  ndbrequire(c_opDropTable.find(dropTabPtr, prep->senderData));
  
  ndbrequire(dropTabPtr.p->m_coordinatorRef == reference());
  ndbrequire(dropTabPtr.p->m_request.tableId == prep->tableId);
  ndbrequire(dropTabPtr.p->m_coordinatorData.m_gsn == GSN_PREP_DROP_TAB_REQ);
  
  Uint32 nodeId = refToNode(prep->senderRef);
  dropTabPtr.p->m_coordinatorData.m_signalCounter.clearWaitingFor(nodeId);
  
  Uint32 block = refToBlock(prep->senderRef);
  if((prep->errorCode == PrepDropTabRef::NoSuchTable && block == DBLQH) ||
     (prep->errorCode == PrepDropTabRef::NF_FakeErrorREF)){
    jam();
    /**
     * Ignore errors:
     * 1) no such table and LQH, it might not exists in different LQH's
     * 2) node failure...
     */
  } else {
    dropTabPtr.p->setErrorCode((Uint32)prep->errorCode);
  }
  
  if(!dropTabPtr.p->m_coordinatorData.m_signalCounter.done()){
    jam();
    return;
  }
  prepDropTab_nextStep(signal, dropTabPtr);
}

void
Dbdict::prepDropTab_complete(Signal* signal, DropTableRecordPtr dropTabPtr){
  jam();

  dropTabPtr.p->m_coordinatorData.m_gsn = GSN_DROP_TAB_REQ;
  dropTabPtr.p->m_coordinatorData.m_block = DBDICT;
  
  DropTabReq * req = (DropTabReq*)signal->getDataPtrSend();
  req->senderRef = reference();
  req->senderData = dropTabPtr.p->key;
  req->tableId = dropTabPtr.p->m_request.tableId;
  req->requestType = dropTabPtr.p->m_requestType;

  dropTabPtr.p->m_coordinatorData.m_signalCounter = c_aliveNodes;
  NodeReceiverGroup rg(DBDICT, c_aliveNodes);
  sendSignal(rg, GSN_DROP_TAB_REQ, signal, 
	     DropTabReq::SignalLength, JBB);
}

void
Dbdict::execDROP_TAB_REF(Signal* signal){
  jamEntry();

  DropTabRef * const req = (DropTabRef*)signal->getDataPtr();

  Uint32 block = refToBlock(req->senderRef);
  ndbrequire(req->errorCode == DropTabRef::NF_FakeErrorREF ||
	     (req->errorCode == DropTabRef::NoSuchTable &&
	      (block == DBTUP || block == DBACC || block == DBLQH)));
  
  if(block != DBDICT){
    jam();
    ndbrequire(refToNode(req->senderRef) == getOwnNodeId());
    dropTab_localDROP_TAB_CONF(signal);
    return;
  }
  ndbrequire(false);
}

void
Dbdict::execDROP_TAB_CONF(Signal* signal){
  jamEntry();

  DropTabConf * const req = (DropTabConf*)signal->getDataPtr();

  if(refToBlock(req->senderRef) != DBDICT){
    jam();
    ndbrequire(refToNode(req->senderRef) == getOwnNodeId());
    dropTab_localDROP_TAB_CONF(signal);
    return;
  }

  DropTableRecordPtr dropTabPtr;  
  ndbrequire(c_opDropTable.find(dropTabPtr, req->senderData));
  
  ndbrequire(dropTabPtr.p->m_coordinatorRef == reference());
  ndbrequire(dropTabPtr.p->m_request.tableId == req->tableId);
  ndbrequire(dropTabPtr.p->m_coordinatorData.m_gsn == GSN_DROP_TAB_REQ);

  Uint32 nodeId = refToNode(req->senderRef);
  dropTabPtr.p->m_coordinatorData.m_signalCounter.clearWaitingFor(nodeId);
  
  if(!dropTabPtr.p->m_coordinatorData.m_signalCounter.done()){
    jam();
    return;
  }
  
  DropTableConf* conf = (DropTableConf*)signal->getDataPtrSend();
  conf->senderRef = reference();
  conf->senderData = dropTabPtr.p->m_request.senderData;
  conf->tableId = dropTabPtr.p->m_request.tableId;
  conf->tableVersion = dropTabPtr.p->m_request.tableVersion;
  
  Uint32 ref = dropTabPtr.p->m_request.senderRef;
  sendSignal(ref, GSN_DROP_TABLE_CONF, signal, 
	     DropTableConf::SignalLength, JBB);

  c_opDropTable.release(dropTabPtr);
  c_blockState = BS_IDLE;
}

/**
 * DROP TABLE PARTICIPANT CODE
 */
void
Dbdict::execPREP_DROP_TAB_REQ(Signal* signal){
  jamEntry();
  PrepDropTabReq * prep = (PrepDropTabReq*)signal->getDataPtrSend();  

  DropTableRecordPtr dropTabPtr;  
  if(prep->senderRef == reference()){
    jam();
    ndbrequire(c_opDropTable.find(dropTabPtr, prep->senderData));
    ndbrequire(dropTabPtr.p->m_requestType == prep->requestType);
  } else {
    jam();
    c_opDropTable.seize(dropTabPtr);
    if(!dropTabPtr.isNull()){
      dropTabPtr.p->key = prep->senderData;
      c_opDropTable.add(dropTabPtr);
    }
  }
  
  ndbrequire(!dropTabPtr.isNull());

  dropTabPtr.p->m_errorCode = 0;
  dropTabPtr.p->m_request.tableId = prep->tableId;
  dropTabPtr.p->m_requestType = prep->requestType;
  dropTabPtr.p->m_coordinatorRef = prep->senderRef;
  dropTabPtr.p->m_participantData.m_gsn = GSN_PREP_DROP_TAB_REQ;

  TableRecordPtr tablePtr;
  c_tableRecordPool.getPtr(tablePtr, prep->tableId);
  tablePtr.p->tabState = TableRecord::PREPARE_DROPPING;
  
  /**
   * Modify schema
   */
  PageRecordPtr pagePtr;
  c_pageRecordArray.getPtr(pagePtr, c_schemaRecord.schemaPage);
  
  SchemaFile::TableEntry * tableEntry = getTableEntry(pagePtr.p, tablePtr.i);
  SchemaFile::TableState tabState = 
    (SchemaFile::TableState)tableEntry->m_tableState;
  ndbrequire(tabState == SchemaFile::TABLE_ADD_COMMITTED ||
	     tabState == SchemaFile::ALTER_TABLE_COMMITTED);
  tableEntry->m_tableState   = SchemaFile::DROP_TABLE_STARTED;
  computeChecksum((SchemaFile*)pagePtr.p);
  
  ndbrequire(c_writeSchemaRecord.inUse == false);
  c_writeSchemaRecord.inUse = true;
  
  c_writeSchemaRecord.pageId = c_schemaRecord.schemaPage;
  c_writeSchemaRecord.m_callback.m_callbackData = dropTabPtr.p->key;
  c_writeSchemaRecord.m_callback.m_callbackFunction = 
    safe_cast(&Dbdict::prepDropTab_writeSchemaConf);
  startWriteSchemaFile(signal);
}

void
Dbdict::prepDropTab_writeSchemaConf(Signal* signal, 
				    Uint32 dropTabPtrI,
				    Uint32 returnCode){
  jam();

  DropTableRecordPtr dropTabPtr;  
  ndbrequire(c_opDropTable.find(dropTabPtr, dropTabPtrI));

  ndbrequire(dropTabPtr.p->m_participantData.m_gsn == GSN_PREP_DROP_TAB_REQ);
  
  /**
   * There probably should be node fail handlign here
   *
   * To check that coordinator hasn't died
   */
  
  PrepDropTabConf * prep = (PrepDropTabConf*)signal->getDataPtr();  
  prep->senderRef = reference();
  prep->senderData = dropTabPtrI;
  prep->tableId = dropTabPtr.p->m_request.tableId;
  
  dropTabPtr.p->m_participantData.m_gsn = GSN_PREP_DROP_TAB_CONF;
  sendSignal(dropTabPtr.p->m_coordinatorRef, GSN_PREP_DROP_TAB_CONF, signal, 
	     PrepDropTabConf::SignalLength, JBB);
}

void
Dbdict::execDROP_TAB_REQ(Signal* signal){
  jamEntry();
  DropTabReq * req = (DropTabReq*)signal->getDataPtrSend();  

  DropTableRecordPtr dropTabPtr;  
  ndbrequire(c_opDropTable.find(dropTabPtr, req->senderData));

  ndbrequire(dropTabPtr.p->m_participantData.m_gsn == GSN_PREP_DROP_TAB_CONF);
  dropTabPtr.p->m_participantData.m_gsn = GSN_DROP_TAB_REQ;

  ndbrequire(dropTabPtr.p->m_requestType == req->requestType);

  TableRecordPtr tablePtr;
  c_tableRecordPool.getPtr(tablePtr, dropTabPtr.p->m_request.tableId);
  tablePtr.p->tabState = TableRecord::DROPPING;

  dropTabPtr.p->m_participantData.m_block = 0;
  dropTabPtr.p->m_participantData.m_callback.m_callbackData = dropTabPtr.p->key;
  dropTabPtr.p->m_participantData.m_callback.m_callbackFunction = 
    safe_cast(&Dbdict::dropTab_complete);
  dropTab_nextStep(signal, dropTabPtr);  
}

#include <DebuggerNames.hpp>

void
Dbdict::dropTab_nextStep(Signal* signal, DropTableRecordPtr dropTabPtr){

  /**
   * No errors currently allowed
   */
  ndbrequire(dropTabPtr.p->m_errorCode == 0);

  TableRecordPtr tablePtr;
  c_tableRecordPool.getPtr(tablePtr, dropTabPtr.p->m_request.tableId);

  Uint32 block = 0;
  switch(dropTabPtr.p->m_participantData.m_block){
  case 0:
    jam();
    block = DBTC;
    break;
  case DBTC:
    jam();
    if (tablePtr.p->isTable() || tablePtr.p->isHashIndex())
      block = DBACC;
    if (tablePtr.p->isOrderedIndex())
      block = DBTUP;
    break;
  case DBACC:
    jam();
    block = DBTUP;
    break;
  case DBTUP:
    jam();
    if (tablePtr.p->isTable() || tablePtr.p->isHashIndex())
      block = DBLQH;
    if (tablePtr.p->isOrderedIndex())
      block = DBTUX;
    break;
  case DBTUX:
    jam();
    block = DBLQH;
    break;
  case DBLQH:
    jam();
    block = DBDIH;
    break;
  case DBDIH:
    jam();
    execute(signal, dropTabPtr.p->m_participantData.m_callback, 0);
    return;
  }
  ndbrequire(block != 0);
  dropTabPtr.p->m_participantData.m_block = block;

  DropTabReq * req = (DropTabReq*)signal->getDataPtrSend();
  req->senderRef = reference();
  req->senderData = dropTabPtr.p->key;
  req->tableId = dropTabPtr.p->m_request.tableId;
  req->requestType = dropTabPtr.p->m_requestType;
  
  const Uint32 nodeId = getOwnNodeId();
  dropTabPtr.p->m_participantData.m_signalCounter.clearWaitingFor();
  dropTabPtr.p->m_participantData.m_signalCounter.setWaitingFor(nodeId);
  BlockReference ref = numberToRef(block, 0);
  sendSignal(ref, GSN_DROP_TAB_REQ, signal, DropTabReq::SignalLength, JBB);
}

void
Dbdict::dropTab_localDROP_TAB_CONF(Signal* signal){
  jamEntry();
  
  DropTabConf * conf = (DropTabConf*)signal->getDataPtr();

  DropTableRecordPtr dropTabPtr;  
  ndbrequire(c_opDropTable.find(dropTabPtr, conf->senderData));
  
  ndbrequire(dropTabPtr.p->m_request.tableId == conf->tableId);
  ndbrequire(dropTabPtr.p->m_participantData.m_gsn == GSN_DROP_TAB_REQ);
  
  Uint32 nodeId = refToNode(conf->senderRef);
  dropTabPtr.p->m_participantData.m_signalCounter.clearWaitingFor(nodeId);
  
  if(!dropTabPtr.p->m_participantData.m_signalCounter.done()){
    jam();
    ndbrequire(false);
    return;
  }
  dropTab_nextStep(signal, dropTabPtr);
}

void
Dbdict::dropTab_complete(Signal* signal, 
			 Uint32 dropTabPtrI,
			 Uint32 returnCode){
  jam();

  DropTableRecordPtr dropTabPtr;  
  ndbrequire(c_opDropTable.find(dropTabPtr, dropTabPtrI));
  
  Uint32 tableId = dropTabPtr.p->m_request.tableId;
  
  /**
   * Write to schema file
   */
  PageRecordPtr pagePtr;
  c_pageRecordArray.getPtr(pagePtr, c_schemaRecord.schemaPage);
  
  SchemaFile::TableEntry * tableEntry = getTableEntry(pagePtr.p, tableId);
  SchemaFile::TableState tabState = 
    (SchemaFile::TableState)tableEntry->m_tableState;
  ndbrequire(tabState == SchemaFile::DROP_TABLE_STARTED);
  tableEntry->m_tableState = SchemaFile::DROP_TABLE_COMMITTED;
  computeChecksum((SchemaFile*)pagePtr.p);
  
  ndbrequire(c_writeSchemaRecord.inUse == false);
  c_writeSchemaRecord.inUse = true;

  c_writeSchemaRecord.pageId = c_schemaRecord.schemaPage;
  c_writeSchemaRecord.m_callback.m_callbackData = dropTabPtr.p->key;
  c_writeSchemaRecord.m_callback.m_callbackFunction = 
    safe_cast(&Dbdict::dropTab_writeSchemaConf);
  startWriteSchemaFile(signal);
}

void
Dbdict::dropTab_writeSchemaConf(Signal* signal, 
				Uint32 dropTabPtrI,
				Uint32 returnCode){
  jam();

  DropTableRecordPtr dropTabPtr;  
  ndbrequire(c_opDropTable.find(dropTabPtr, dropTabPtrI));

  ndbrequire(dropTabPtr.p->m_participantData.m_gsn == GSN_DROP_TAB_REQ);

  dropTabPtr.p->m_participantData.m_gsn = GSN_DROP_TAB_CONF;

  releaseTableObject(dropTabPtr.p->m_request.tableId);

  DropTabConf * conf = (DropTabConf*)signal->getDataPtr();  
  conf->senderRef = reference();
  conf->senderData = dropTabPtrI;
  conf->tableId = dropTabPtr.p->m_request.tableId;
  
  dropTabPtr.p->m_participantData.m_gsn = GSN_DROP_TAB_CONF;
  sendSignal(dropTabPtr.p->m_coordinatorRef, GSN_DROP_TAB_CONF, signal, 
	     DropTabConf::SignalLength, JBB);
  
  if(dropTabPtr.p->m_coordinatorRef != reference()){
    c_opDropTable.release(dropTabPtr);
  }
}

void Dbdict::releaseTableObject(Uint32 tableId, bool removeFromHash) 
{
  TableRecordPtr tablePtr;
  AttributeRecordPtr attrPtr;
  c_tableRecordPool.getPtr(tablePtr, tableId);
  if (removeFromHash)
  {
#ifdef VM_TRACE
    TableRecordPtr tmp;
    ndbrequire(c_tableRecordHash.find(tmp, * tablePtr.p));
#endif
    c_tableRecordHash.remove(tablePtr);
  }
  tablePtr.p->tabState = TableRecord::NOT_DEFINED;

  Uint32 nextAttrRecord = tablePtr.p->firstAttribute;
  while (nextAttrRecord != RNIL) {
    jam();
/* ---------------------------------------------------------------- */
// Release all attribute records
/* ---------------------------------------------------------------- */
    c_attributeRecordPool.getPtr(attrPtr, nextAttrRecord);
    nextAttrRecord = attrPtr.p->nextAttrInTable;
    c_attributeRecordPool.release(attrPtr);
  }//if
#ifdef HAVE_TABLE_REORG
  Uint32 secondTableId = tablePtr.p->secondTable;
  initialiseTableRecord(tablePtr);
  c_tableRecordPool.getPtr(tablePtr, secondTableId);
  initialiseTableRecord(tablePtr);
#endif
  return; 
}//releaseTableObject()

/**
 * DICT receives these on index create and drop.
 */
void Dbdict::execDROP_TABLE_CONF(Signal* signal) 
{
  jamEntry();
  ndbrequire(signal->getNoOfSections() == 0);

  DropTableConf * const conf = (DropTableConf *)signal->getDataPtr();
  // assume part of drop index operation
  OpDropIndexPtr opPtr;
  c_opDropIndex.find(opPtr, conf->senderData);
  ndbrequire(! opPtr.isNull());
  ndbrequire(opPtr.p->m_request.getIndexId() == conf->tableId);
  ndbrequire(opPtr.p->m_request.getIndexVersion() == conf->tableVersion);
  dropIndex_fromDropTable(signal, opPtr);
}

void Dbdict::execDROP_TABLE_REF(Signal* signal) 
{
  jamEntry();

  DropTableRef * const ref = (DropTableRef *)signal->getDataPtr();
  // assume part of drop index operation
  OpDropIndexPtr opPtr;
  c_opDropIndex.find(opPtr, ref->senderData);
  ndbrequire(! opPtr.isNull());
  opPtr.p->setError(ref);
  opPtr.p->m_errorLine = __LINE__;
  dropIndex_fromDropTable(signal, opPtr);
}

/* **************************************************************** */
/* ---------------------------------------------------------------- */
/* MODULE:          EXTERNAL INTERFACE TO DATA -------------------- */
/* ---------------------------------------------------------------- */
/*                                                                  */
/* This module contains the code that is used by other modules to.  */
/* access the data within DBDICT.                                   */
/* ---------------------------------------------------------------- */
/* **************************************************************** */

void Dbdict::execGET_TABLEDID_REQ(Signal * signal) 
{
  jamEntry();
  ndbrequire(signal->getNoOfSections() == 1);  
  GetTableIdReq const * req = (GetTableIdReq *)signal->getDataPtr();
  Uint32 senderData = req->senderData;
  Uint32 senderRef = req->senderRef;
  Uint32 len = req->len;

  if(len>MAX_TAB_NAME_SIZE)
  {
    jam();
    sendGET_TABLEID_REF((Signal*)signal, 
			(GetTableIdReq *)req, 
			GetTableIdRef::TableNameTooLong);
    return;
  }

  char tableName[MAX_TAB_NAME_SIZE];
  TableRecord keyRecord;
  SegmentedSectionPtr ssPtr;
  signal->getSection(ssPtr,GetTableIdReq::TABLE_NAME);
  copy((Uint32*)tableName, ssPtr);
  strcpy(keyRecord.tableName, tableName);
  releaseSections(signal);

  if(len > sizeof(keyRecord.tableName)){
    jam();
    sendGET_TABLEID_REF((Signal*)signal, 
			(GetTableIdReq *)req, 
			GetTableIdRef::TableNameTooLong);
    return;
  }
  
  TableRecordPtr tablePtr;
  if(!c_tableRecordHash.find(tablePtr, keyRecord)) {
    jam();
    sendGET_TABLEID_REF((Signal*)signal, 
			(GetTableIdReq *)req, 
			GetTableIdRef::TableNotDefined);
    return;
  }
  GetTableIdConf * conf = (GetTableIdConf *)req;
  conf->tableId               = tablePtr.p->tableId;
  conf->schemaVersion         = tablePtr.p->tableVersion;
  conf->senderData            = senderData;
  sendSignal(senderRef, GSN_GET_TABLEID_CONF, signal,
	     GetTableIdConf::SignalLength, JBB);  
  
}


void Dbdict::sendGET_TABLEID_REF(Signal* signal, 
				 GetTableIdReq * req,
				 GetTableIdRef::ErrorCode errorCode) 
{
  GetTableIdRef * const ref = (GetTableIdRef *)req;
  /**
   * The format of GetTabInfo Req/Ref is the same
   */
  BlockReference retRef = req->senderRef;
  ref->err  = errorCode;
  sendSignal(retRef, GSN_GET_TABLEID_REF, signal, 
	     GetTableIdRef::SignalLength, JBB);
}//sendGET_TABINFOREF()

/* ---------------------------------------------------------------- */
// Get a full table description.
/* ---------------------------------------------------------------- */
void Dbdict::execGET_TABINFOREQ(Signal* signal) 
{
  jamEntry();
  if(!assembleFragments(signal)) 
  { 
    return;
  }  

  GetTabInfoReq * const req = (GetTabInfoReq *)&signal->theData[0];

  /**
   * If I get a GET_TABINFO_REQ from myself
   * it's is a one from the time queue
   */
  bool fromTimeQueue = (signal->senderBlockRef() == reference());
  
  if (c_retrieveRecord.busyState && fromTimeQueue == true) {
    jam();
    
    sendSignalWithDelay(reference(), GSN_GET_TABINFOREQ, signal, 30, 
			signal->length());
    return;
  }//if

  const Uint32 MAX_WAITERS = 5;
  
  if(c_retrieveRecord.busyState && fromTimeQueue == false){
    jam();
    if(c_retrieveRecord.noOfWaiters < MAX_WAITERS){
      jam();
      c_retrieveRecord.noOfWaiters++;
      
      sendSignalWithDelay(reference(), GSN_GET_TABINFOREQ, signal, 30, 
			  signal->length());
      return;
    }
    
    sendGET_TABINFOREF(signal, req, GetTabInfoRef::Busy);
    return;
  }
  
  if(fromTimeQueue){
    jam();
    c_retrieveRecord.noOfWaiters--;
  } 

  const bool useLongSig = (req->requestType & GetTabInfoReq::LongSignalConf);
  const Uint32 reqType = req->requestType & (~GetTabInfoReq::LongSignalConf);
  
  TableRecordPtr tablePtr;
  if(reqType == GetTabInfoReq::RequestByName){
    jam();
    ndbrequire(signal->getNoOfSections() == 1);  
    const Uint32 len = req->tableNameLen;
    
    TableRecord keyRecord;
    if(len > sizeof(keyRecord.tableName)){
      jam();
      releaseSections(signal);
      sendGET_TABINFOREF(signal, req, GetTabInfoRef::TableNameTooLong);
      return;
    }

    char tableName[MAX_TAB_NAME_SIZE];
    SegmentedSectionPtr ssPtr;
    signal->getSection(ssPtr,GetTabInfoReq::TABLE_NAME);
    SimplePropertiesSectionReader r0(ssPtr, getSectionSegmentPool());
    r0.reset(); // undo implicit first()
    if(r0.getWords((Uint32*)tableName, ((len + 3)/4)))
      memcpy(keyRecord.tableName, tableName, len);
    else {
      jam();
      releaseSections(signal);
      sendGET_TABINFOREF(signal, req, GetTabInfoRef::TableNotDefined);
      return;
    }
    releaseSections(signal);
    //    memcpy(keyRecord.tableName, req->tableName, len);
    //ntohS(&keyRecord.tableName[0], len);
   
    c_tableRecordHash.find(tablePtr, keyRecord);
  } else {
    jam();
    c_tableRecordPool.getPtr(tablePtr, req->tableId, false);
  }
  
  // The table seached for was not found
  if(tablePtr.i == RNIL){
    jam();
    sendGET_TABINFOREF(signal, req, GetTabInfoRef::InvalidTableId);
    return;
  }//if
  
  if (tablePtr.p->tabState != TableRecord::DEFINED) {
    jam();
    sendGET_TABINFOREF(signal, req, GetTabInfoRef::TableNotDefined);
    return;
  }//if
  
  c_retrieveRecord.busyState = true;
  c_retrieveRecord.blockRef = req->senderRef;
  c_retrieveRecord.m_senderData = req->senderData;
  c_retrieveRecord.tableId = tablePtr.i;
  c_retrieveRecord.currentSent = 0;
  c_retrieveRecord.m_useLongSig = useLongSig;
  
  c_packTable.m_state = PackTable::PTS_GET_TAB;
  
  signal->theData[0] = ZPACK_TABLE_INTO_PAGES;
  signal->theData[1] = tablePtr.i;
  signal->theData[2] = c_retrieveRecord.retrievePage;  
  sendSignal(reference(), GSN_CONTINUEB, signal, 3, JBB);
}//execGET_TABINFOREQ()

void Dbdict::sendGetTabResponse(Signal* signal) 
{
  PageRecordPtr pagePtr;
  DictTabInfo * const conf = (DictTabInfo *)&signal->theData[0];
  conf->senderRef   = reference();
  conf->senderData  = c_retrieveRecord.m_senderData;
  conf->requestType = DictTabInfo::GetTabInfoConf;
  conf->totalLen    = c_retrieveRecord.retrievedNoOfWords;

  c_pageRecordArray.getPtr(pagePtr, c_retrieveRecord.retrievePage);
  Uint32* pagePointer = (Uint32*)&pagePtr.p->word[0] + ZPAGE_HEADER_SIZE;
  
  if(c_retrieveRecord.m_useLongSig){
    jam();
    GetTabInfoConf* conf = (GetTabInfoConf*)signal->getDataPtr();
    conf->gci = 0;
    conf->tableId = c_retrieveRecord.tableId;
    conf->senderData = c_retrieveRecord.m_senderData;
    conf->totalLen = c_retrieveRecord.retrievedNoOfWords;
    
    Callback c = { safe_cast(&Dbdict::initRetrieveRecord), 0 };
    LinearSectionPtr ptr[3];
    ptr[0].p = pagePointer;
    ptr[0].sz = c_retrieveRecord.retrievedNoOfWords;
    sendFragmentedSignal(c_retrieveRecord.blockRef,
			 GSN_GET_TABINFO_CONF,
			 signal, 
			 GetTabInfoConf::SignalLength,
			 JBB,
			 ptr,
			 1,
			 c);
    return;
  }

  ndbrequire(false);
}//sendGetTabResponse()

void Dbdict::sendGET_TABINFOREF(Signal* signal, 
				GetTabInfoReq * req,
				GetTabInfoRef::ErrorCode errorCode) 
{
  jamEntry();
  GetTabInfoRef * const ref = (GetTabInfoRef *)&signal->theData[0];
  /**
   * The format of GetTabInfo Req/Ref is the same
   */
  BlockReference retRef = req->senderRef;
  ref->errorCode = errorCode;
  
  sendSignal(retRef, GSN_GET_TABINFOREF, signal, signal->length(), JBB);
}//sendGET_TABINFOREF()

Uint32 convertEndian(Uint32 in) {
#ifdef WORDS_BIGENDIAN
  Uint32 ut = 0;
  ut += ((in >> 24) & 255);
  ut += (((in >> 16) & 255) << 8);
  ut += (((in >> 8) & 255) << 16);
  ut += ((in & 255) << 24);
  return ut;
#else
  return in;
#endif
}
void
Dbdict::execLIST_TABLES_REQ(Signal* signal)
{
  jamEntry();
  Uint32 i;
  ListTablesReq * req = (ListTablesReq*)signal->getDataPtr();
  Uint32 senderRef  = req->senderRef;
  Uint32 senderData = req->senderData;
  // save req flags
  const Uint32 reqTableId = req->getTableId();
  const Uint32 reqTableType = req->getTableType();
  const bool reqListNames = req->getListNames();
  const bool reqListIndexes = req->getListIndexes();
  // init the confs
  ListTablesConf * conf = (ListTablesConf *)signal->getDataPtrSend();
  conf->senderData = senderData;
  conf->counter = 0;
  Uint32 pos = 0;
  for (i = 0; i < c_tableRecordPool.getSize(); i++) {
    TableRecordPtr tablePtr;
    c_tableRecordPool.getPtr(tablePtr, i);
    // filter
    if (tablePtr.p->tabState == TableRecord::NOT_DEFINED ||
        tablePtr.p->tabState == TableRecord::REORG_TABLE_PREPARED)
      continue;


    if ((reqTableType != (Uint32)0) && (reqTableType != (unsigned)tablePtr.p->tableType))
      continue;
    if (reqListIndexes && reqTableId != tablePtr.p->primaryTableId)
      continue;
    conf->tableData[pos] = 0;
    // id
    conf->setTableId(pos, tablePtr.i);
    // type
    conf->setTableType(pos, tablePtr.p->tableType);
    // state
    if (tablePtr.p->isTable()) {
      switch (tablePtr.p->tabState) {
      case TableRecord::DEFINING:
      case TableRecord::CHECKED:
        conf->setTableState(pos, DictTabInfo::StateBuilding);
        break;
      case TableRecord::PREPARE_DROPPING:
      case TableRecord::DROPPING:
        conf->setTableState(pos, DictTabInfo::StateDropping);
        break;
      case TableRecord::DEFINED:
        conf->setTableState(pos, DictTabInfo::StateOnline);
        break;
      default:
        conf->setTableState(pos, DictTabInfo::StateBroken);
        break;
      }
    }
    if (tablePtr.p->isIndex()) {
      switch (tablePtr.p->indexState) {
      case TableRecord::IS_OFFLINE:
        conf->setTableState(pos, DictTabInfo::StateOffline);
        break;
      case TableRecord::IS_BUILDING:
        conf->setTableState(pos, DictTabInfo::StateBuilding);
        break;
      case TableRecord::IS_DROPPING:
        conf->setTableState(pos, DictTabInfo::StateDropping);
        break;
      case TableRecord::IS_ONLINE:
        conf->setTableState(pos, DictTabInfo::StateOnline);
        break;
      default:
        conf->setTableState(pos, DictTabInfo::StateBroken);
        break;
      }
    }
    // store
    if (! tablePtr.p->storedTable) {
      conf->setTableStore(pos, DictTabInfo::StoreTemporary);
    } else {
      conf->setTableStore(pos, DictTabInfo::StorePermanent);
    }
    pos++;
    if (pos >= ListTablesConf::DataLength) {
      sendSignal(senderRef, GSN_LIST_TABLES_CONF, signal,
		 ListTablesConf::SignalLength, JBB);
      conf->counter++;
      pos = 0;
    }
    if (! reqListNames)
      continue;
    const Uint32 size = strlen(tablePtr.p->tableName) + 1;
    conf->tableData[pos] = size;
    pos++;
    if (pos >= ListTablesConf::DataLength) {
      sendSignal(senderRef, GSN_LIST_TABLES_CONF, signal,
		 ListTablesConf::SignalLength, JBB);
      conf->counter++;
      pos = 0;
    }
    Uint32 k = 0;
    while (k < size) {
      char* p = (char*)&conf->tableData[pos];
      for (Uint32 j = 0; j < 4; j++) {
        if (k < size)
          *p++ = tablePtr.p->tableName[k++];
        else
          *p++ = 0;
      }
      pos++;
      if (pos >= ListTablesConf::DataLength) {
        sendSignal(senderRef, GSN_LIST_TABLES_CONF, signal,
                   ListTablesConf::SignalLength, JBB);
        conf->counter++;
        pos = 0;
      }
    }
  }
  // XXX merge with above somehow
  for (i = 0; i < c_triggerRecordPool.getSize(); i++) {
    if (reqListIndexes)
      break;
    TriggerRecordPtr triggerPtr;
    c_triggerRecordPool.getPtr(triggerPtr, i);
    if (triggerPtr.p->triggerState == TriggerRecord::TS_NOT_DEFINED)
      continue;
    // constant 10 hardcoded
    Uint32 type = 10 + triggerPtr.p->triggerType;
    if (reqTableType != 0 && reqTableType != type)
      continue;
    conf->tableData[pos] = 0;
    conf->setTableId(pos, triggerPtr.i);
    conf->setTableType(pos, type);
    switch (triggerPtr.p->triggerState) {
    case TriggerRecord::TS_OFFLINE:
      conf->setTableState(pos, DictTabInfo::StateOffline);
      break;
    case TriggerRecord::TS_ONLINE:
      conf->setTableState(pos, DictTabInfo::StateOnline);
      break;
    default:
      conf->setTableState(pos, DictTabInfo::StateBroken);
      break;
    }
    conf->setTableStore(pos, DictTabInfo::StoreTemporary);
    pos++;
    if (pos >= ListTablesConf::DataLength) {
      sendSignal(senderRef, GSN_LIST_TABLES_CONF, signal,
        ListTablesConf::SignalLength, JBB);
      conf->counter++;
      pos = 0;
    }
    if (! reqListNames)
      continue;
    const Uint32 size = strlen(triggerPtr.p->triggerName) + 1;
    conf->tableData[pos] = size;
    pos++;
    if (pos >= ListTablesConf::DataLength) {
      sendSignal(senderRef, GSN_LIST_TABLES_CONF, signal,
		 ListTablesConf::SignalLength, JBB);
      conf->counter++;
      pos = 0;
    }
    Uint32 k = 0;
    while (k < size) {
      char* p = (char*)&conf->tableData[pos];
      for (Uint32 j = 0; j < 4; j++) {
        if (k < size)
          *p++ = triggerPtr.p->triggerName[k++];
        else
          *p++ = 0;
      }
      pos++;
      if (pos >= ListTablesConf::DataLength) {
        sendSignal(senderRef, GSN_LIST_TABLES_CONF, signal,
                   ListTablesConf::SignalLength, JBB);
        conf->counter++;
        pos = 0;
      }
    }
  }
  // last signal must have less than max length
  sendSignal(senderRef, GSN_LIST_TABLES_CONF, signal,
	     ListTablesConf::HeaderLength + pos, JBB);
}

/**
 * MODULE: Create index
 *
 * Create index in DICT via create table operation.  Then invoke alter
 * index opearation to online the index.
 *
 * Request type in CREATE_INDX signals:
 *
 * RT_USER - from API to DICT master
 * RT_DICT_PREPARE - prepare participants
 * RT_DICT_COMMIT - commit participants
 * RT_TC - create index in TC (part of alter index operation)
 */

void
Dbdict::execCREATE_INDX_REQ(Signal* signal)
{
  jamEntry();
  CreateIndxReq* const req = (CreateIndxReq*)signal->getDataPtrSend();
  OpCreateIndexPtr opPtr;
  const Uint32 senderRef = signal->senderBlockRef();
  const CreateIndxReq::RequestType requestType = req->getRequestType();
  if (requestType == CreateIndxReq::RT_USER) {
    jam();
    if (! assembleFragments(signal)) {
      jam();
      return;
    }
    if (signal->getLength() == CreateIndxReq::SignalLength) {
      jam();
      if (getOwnNodeId() != c_masterNodeId) {
        jam();
        // forward to DICT master
        sendSignal(calcDictBlockRef(c_masterNodeId), GSN_CREATE_INDX_REQ,
            signal, signal->getLength(), JBB);
        return;
      }
      // forward initial request plus operation key to all
      req->setOpKey(++c_opRecordSequence);
      NodeReceiverGroup rg(DBDICT, c_aliveNodes);
      sendSignal(rg, GSN_CREATE_INDX_REQ,
          signal, CreateIndxReq::SignalLength + 1, JBB);
      return;
    }
    // seize operation record
    ndbrequire(signal->getLength() == CreateIndxReq::SignalLength + 1);
    const Uint32 opKey = req->getOpKey();
    OpCreateIndex opBusy;
    if (! c_opCreateIndex.seize(opPtr))
      opPtr.p = &opBusy;
    opPtr.p->save(req);
    opPtr.p->m_coordinatorRef = senderRef;
    opPtr.p->m_isMaster = (senderRef == reference());
    opPtr.p->key = opKey;
    opPtr.p->m_requestType = CreateIndxReq::RT_DICT_PREPARE;
    if (opPtr.p == &opBusy) {
      jam();
      opPtr.p->m_errorCode = CreateIndxRef::Busy;
      opPtr.p->m_errorLine = __LINE__;
      releaseSections(signal);
      createIndex_sendReply(signal, opPtr, opPtr.p->m_isMaster);
      return;
    }
    c_opCreateIndex.add(opPtr);
    // save attribute list
    SegmentedSectionPtr ssPtr;
    signal->getSection(ssPtr, CreateIndxReq::ATTRIBUTE_LIST_SECTION);
    SimplePropertiesSectionReader r0(ssPtr, getSectionSegmentPool());
    r0.reset(); // undo implicit first()
    if (! r0.getWord(&opPtr.p->m_attrList.sz) ||
        ! r0.getWords(opPtr.p->m_attrList.id, opPtr.p->m_attrList.sz)) {
      jam();
      opPtr.p->m_errorCode = CreateIndxRef::InvalidName;
      opPtr.p->m_errorLine = __LINE__;
      releaseSections(signal);
      createIndex_sendReply(signal, opPtr, opPtr.p->m_isMaster);
      return;
    }
    // save name and index table properties
    signal->getSection(ssPtr, CreateIndxReq::INDEX_NAME_SECTION);
    SimplePropertiesSectionReader r1(ssPtr, getSectionSegmentPool());
    DictTabInfo::Table tableDesc;
    tableDesc.init();
    SimpleProperties::UnpackStatus status = SimpleProperties::unpack(
        r1, &tableDesc,
        DictTabInfo::TableMapping, DictTabInfo::TableMappingSize,
        true, true);
    if (status != SimpleProperties::Eof) {
      opPtr.p->m_errorCode = CreateIndxRef::InvalidName;
      opPtr.p->m_errorLine = __LINE__;
      releaseSections(signal);
      createIndex_sendReply(signal, opPtr, opPtr.p->m_isMaster);
      return;
    }
    memcpy(opPtr.p->m_indexName, tableDesc.TableName, MAX_TAB_NAME_SIZE);
    opPtr.p->m_storedIndex = tableDesc.TableLoggedFlag;
    releaseSections(signal);
    // master expects to hear from all
    if (opPtr.p->m_isMaster)
      opPtr.p->m_signalCounter = c_aliveNodes;
    createIndex_slavePrepare(signal, opPtr);
    createIndex_sendReply(signal, opPtr, false);
    return;
  }
  c_opCreateIndex.find(opPtr, req->getConnectionPtr());
  if (! opPtr.isNull()) {
    opPtr.p->m_requestType = requestType;
    if (requestType == CreateIndxReq::RT_DICT_COMMIT ||
        requestType == CreateIndxReq::RT_DICT_ABORT) {
      jam();
      if (requestType == CreateIndxReq::RT_DICT_COMMIT) {
        opPtr.p->m_request.setIndexId(req->getIndexId());
        opPtr.p->m_request.setIndexVersion(req->getIndexVersion());
        createIndex_slaveCommit(signal, opPtr);
      } else {
        createIndex_slaveAbort(signal, opPtr);
      }
      createIndex_sendReply(signal, opPtr, false);
      // done in slave
      if (! opPtr.p->m_isMaster)
        c_opCreateIndex.release(opPtr);
      return;
    }
  }
  jam();
  // return to sender
  releaseSections(signal);
  OpCreateIndex opBad;
  opPtr.p = &opBad;
  opPtr.p->save(req);
  opPtr.p->m_errorCode = CreateIndxRef::BadRequestType;
  opPtr.p->m_errorLine = __LINE__;
  createIndex_sendReply(signal, opPtr, true);
}

void
Dbdict::execCREATE_INDX_CONF(Signal* signal)
{
  jamEntry();
  ndbrequire(signal->getNoOfSections() == 0);
  CreateIndxConf* conf = (CreateIndxConf*)signal->getDataPtrSend();
  createIndex_recvReply(signal, conf, 0);
}

void
Dbdict::execCREATE_INDX_REF(Signal* signal) 
{
  jamEntry();      
  CreateIndxRef* ref = (CreateIndxRef*)signal->getDataPtrSend();
  createIndex_recvReply(signal, ref->getConf(), ref);
}

void
Dbdict::createIndex_recvReply(Signal* signal, const CreateIndxConf* conf,
    const CreateIndxRef* ref)
{
  jam();
  const Uint32 senderRef = signal->senderBlockRef();
  const CreateIndxReq::RequestType requestType = conf->getRequestType();
  const Uint32 key = conf->getConnectionPtr();
  if (requestType == CreateIndxReq::RT_TC) {
    jam();
    // part of alter index operation
    OpAlterIndexPtr opPtr;
    c_opAlterIndex.find(opPtr, key);
    ndbrequire(! opPtr.isNull());
    opPtr.p->setError(ref);
    alterIndex_fromCreateTc(signal, opPtr);
    return;
  }
  OpCreateIndexPtr opPtr;
  c_opCreateIndex.find(opPtr, key);
  ndbrequire(! opPtr.isNull());
  ndbrequire(opPtr.p->m_isMaster);
  ndbrequire(opPtr.p->m_requestType == requestType);
  opPtr.p->setError(ref);
  opPtr.p->m_signalCounter.clearWaitingFor(refToNode(senderRef));
  if (! opPtr.p->m_signalCounter.done()) {
    jam();
    return;
  }
  if (requestType == CreateIndxReq::RT_DICT_COMMIT ||
      requestType == CreateIndxReq::RT_DICT_ABORT) {
    jam();
    // send reply to user
    createIndex_sendReply(signal, opPtr, true);
    c_opCreateIndex.release(opPtr);
    return;
  }
  if (opPtr.p->hasError()) {
    jam();
    opPtr.p->m_requestType = CreateIndxReq::RT_DICT_ABORT;
    createIndex_sendSlaveReq(signal, opPtr);
    return;
  }
  if (requestType == CreateIndxReq::RT_DICT_PREPARE) {
    jam();
    // start index table create
    createIndex_toCreateTable(signal, opPtr);
    if (opPtr.p->hasError()) {
      jam();
      opPtr.p->m_requestType = CreateIndxReq::RT_DICT_ABORT;
      createIndex_sendSlaveReq(signal, opPtr);
      return;
    }
    return;
  }
  ndbrequire(false);
}

void
Dbdict::createIndex_slavePrepare(Signal* signal, OpCreateIndexPtr opPtr)
{
  jam();
}

void
Dbdict::createIndex_toCreateTable(Signal* signal, OpCreateIndexPtr opPtr)
{
  Uint32 attrid_map[MAX_ATTRIBUTES_IN_INDEX];
  Uint32 k;
  jam();
  const CreateIndxReq* const req = &opPtr.p->m_request;
  // signal data writer
  Uint32* wbuffer = &c_indexPage.word[0];
  LinearWriter w(wbuffer, sizeof(c_indexPage) >> 2);
  w.first();
  // get table being indexed
  if (! (req->getTableId() < c_tableRecordPool.getSize())) {
    jam();
    opPtr.p->m_errorCode = CreateIndxRef::InvalidPrimaryTable;
    opPtr.p->m_errorLine = __LINE__;
    return;
  }
  TableRecordPtr tablePtr;
  c_tableRecordPool.getPtr(tablePtr, req->getTableId());
  if (tablePtr.p->tabState != TableRecord::DEFINED) {
    jam();
    opPtr.p->m_errorCode = CreateIndxRef::InvalidPrimaryTable;
    opPtr.p->m_errorLine = __LINE__;
    return;
  }
  if (! tablePtr.p->isTable()) {
    jam();
    opPtr.p->m_errorCode = CreateIndxRef::InvalidPrimaryTable;
    opPtr.p->m_errorLine = __LINE__;
    return;
  }
  // compute index table record
  TableRecord indexRec;
  TableRecordPtr indexPtr;
  indexPtr.i = RNIL;            // invalid
  indexPtr.p = &indexRec;
  initialiseTableRecord(indexPtr);
  if (req->getIndexType() == DictTabInfo::UniqueHashIndex) {
    indexPtr.p->storedTable = opPtr.p->m_storedIndex;
    indexPtr.p->fragmentType = tablePtr.p->fragmentType;
  } else if (req->getIndexType() == DictTabInfo::OrderedIndex) {
    // first version will not supported logging
    if (opPtr.p->m_storedIndex) {
      jam();
      opPtr.p->m_errorCode = CreateIndxRef::InvalidIndexType;
      opPtr.p->m_errorLine = __LINE__;
      return;
    }
    indexPtr.p->storedTable = false;
    // follows table fragmentation
    indexPtr.p->fragmentType = tablePtr.p->fragmentType;
  } else {
    jam();
    opPtr.p->m_errorCode = CreateIndxRef::InvalidIndexType;
    opPtr.p->m_errorLine = __LINE__;
    return;
  }
  indexPtr.p->tableType = (DictTabInfo::TableType)req->getIndexType();
  indexPtr.p->primaryTableId = req->getTableId();
  indexPtr.p->noOfAttributes = opPtr.p->m_attrList.sz;
  indexPtr.p->tupKeyLength = 0;
  if (indexPtr.p->noOfAttributes == 0) {
    jam();
    opPtr.p->m_errorCode = CreateIndxRef::InvalidIndexType;
    opPtr.p->m_errorLine = __LINE__;
    return;
  }
  if (indexPtr.p->isOrderedIndex()) {
    // tree node size in words (make configurable later)
    indexPtr.p->tupKeyLength = MAX_TTREE_NODE_SIZE;
  }

  AttributeMask mask;
  mask.clear();
  for (k = 0; k < opPtr.p->m_attrList.sz; k++) {
    jam();
    unsigned current_id= opPtr.p->m_attrList.id[k];
    AttributeRecord* aRec= NULL;
    Uint32 tAttr= tablePtr.p->firstAttribute;
    for (; tAttr != RNIL; tAttr= aRec->nextAttrInTable)
    {
      aRec = c_attributeRecordPool.getPtr(tAttr);
      if (aRec->attributeId != current_id)
        continue;
      jam();
      break;
    }
    if (tAttr == RNIL) {
      jam();
      opPtr.p->m_errorCode = CreateIndxRef::BadRequestType;
      opPtr.p->m_errorLine = __LINE__;
      return;
    }
    if (mask.get(current_id))
    {
      jam();
      opPtr.p->m_errorCode = CreateIndxRef::DuplicateAttributes;
      opPtr.p->m_errorLine = __LINE__;
      return;
    }
    mask.set(current_id);

    const Uint32 a = aRec->attributeDescriptor;
    unsigned kk= k;
    if (indexPtr.p->isHashIndex()) {
      const Uint32 s1 = AttributeDescriptor::getSize(a);
      const Uint32 s2 = AttributeDescriptor::getArraySize(a);
      indexPtr.p->tupKeyLength += ((1 << s1) * s2 + 31) >> 5;
      // reorder the attributes according to the tableid order
      // for unque indexes
      for (; kk > 0 && current_id < attrid_map[kk-1]>>16; kk--)
	attrid_map[kk]= attrid_map[kk-1];
    }
    attrid_map[kk]= k | (current_id << 16);
  }
  indexPtr.p->noOfPrimkey = indexPtr.p->noOfAttributes;
  // plus concatenated primary table key attribute
  indexPtr.p->noOfAttributes += 1;
  indexPtr.p->noOfNullAttr = 0;
  // write index table
  w.add(DictTabInfo::TableName, opPtr.p->m_indexName);
  w.add(DictTabInfo::TableLoggedFlag, indexPtr.p->storedTable);
  w.add(DictTabInfo::FragmentTypeVal, indexPtr.p->fragmentType);
  w.add(DictTabInfo::TableTypeVal, indexPtr.p->tableType);
  w.add(DictTabInfo::PrimaryTable, tablePtr.p->tableName);
  w.add(DictTabInfo::PrimaryTableId, tablePtr.i);
  w.add(DictTabInfo::NoOfAttributes, indexPtr.p->noOfAttributes);
  w.add(DictTabInfo::NoOfKeyAttr, indexPtr.p->noOfPrimkey);
  w.add(DictTabInfo::NoOfNullable, indexPtr.p->noOfNullAttr);
  w.add(DictTabInfo::KeyLength, indexPtr.p->tupKeyLength);
  // write index key attributes
  AttributeRecordPtr aRecPtr;
  c_attributeRecordPool.getPtr(aRecPtr, tablePtr.p->firstAttribute);
  for (unsigned k = 0; k < opPtr.p->m_attrList.sz; k++) {
    // insert the attributes in the order decided above in attrid_map
    // k is new order, current_id is in previous order
    // ToDo: make sure "current_id" is stored with the table and
    // passed up to NdbDictionary
    unsigned current_id= opPtr.p->m_attrList.id[attrid_map[k] & 0xffff];
    jam();
    for (Uint32 tAttr = tablePtr.p->firstAttribute; tAttr != RNIL; ) {
      AttributeRecord* aRec = c_attributeRecordPool.getPtr(tAttr);
      tAttr = aRec->nextAttrInTable;
      if (aRec->attributeId != current_id)
        continue;
      jam();
      const Uint32 a = aRec->attributeDescriptor;
      bool isNullable = AttributeDescriptor::getNullable(a);
      Uint32 attrType = AttributeDescriptor::getType(a);
      w.add(DictTabInfo::AttributeName, aRec->attributeName);
      w.add(DictTabInfo::AttributeId, k);
      if (indexPtr.p->isHashIndex()) {
        w.add(DictTabInfo::AttributeKeyFlag, (Uint32)true);
        w.add(DictTabInfo::AttributeNullableFlag, (Uint32)false);
      }
      if (indexPtr.p->isOrderedIndex()) {
        w.add(DictTabInfo::AttributeKeyFlag, (Uint32)false);
        w.add(DictTabInfo::AttributeNullableFlag, (Uint32)isNullable);
      }
      w.add(DictTabInfo::AttributeExtType, attrType);
      w.add(DictTabInfo::AttributeExtPrecision, aRec->extPrecision);
      w.add(DictTabInfo::AttributeExtScale, aRec->extScale);
      w.add(DictTabInfo::AttributeExtLength, aRec->extLength);
      w.add(DictTabInfo::AttributeEnd, (Uint32)true);
    }
  }
  if (indexPtr.p->isHashIndex()) {
    jam();
    // write concatenated primary table key attribute
    w.add(DictTabInfo::AttributeName, "NDB$PK");
    w.add(DictTabInfo::AttributeId, opPtr.p->m_attrList.sz);
    w.add(DictTabInfo::AttributeKeyFlag, (Uint32)false);
    w.add(DictTabInfo::AttributeNullableFlag, (Uint32)false);
    w.add(DictTabInfo::AttributeExtType, (Uint32)DictTabInfo::ExtUnsigned);
    w.add(DictTabInfo::AttributeExtLength, tablePtr.p->tupKeyLength);
    w.add(DictTabInfo::AttributeEnd, (Uint32)true);
  }
  if (indexPtr.p->isOrderedIndex()) {
    jam();
    // write index tree node as Uint32 array attribute
    w.add(DictTabInfo::AttributeName, "NDB$TNODE");
    w.add(DictTabInfo::AttributeId, opPtr.p->m_attrList.sz);
    w.add(DictTabInfo::AttributeKeyFlag, (Uint32)true);
    w.add(DictTabInfo::AttributeNullableFlag, (Uint32)false);
    w.add(DictTabInfo::AttributeExtType, (Uint32)DictTabInfo::ExtUnsigned);
    w.add(DictTabInfo::AttributeExtLength, indexPtr.p->tupKeyLength);
    w.add(DictTabInfo::AttributeEnd, (Uint32)true);
  }
  // finish
  w.add(DictTabInfo::TableEnd, (Uint32)true);
  // remember to...
  releaseSections(signal);
  // send create index table request
  CreateTableReq * const cre = (CreateTableReq*)signal->getDataPtrSend();
  cre->senderRef = reference();
  cre->senderData = opPtr.p->key;
  LinearSectionPtr lsPtr[3];
  lsPtr[0].p = wbuffer;
  lsPtr[0].sz = w.getWordsUsed();
  sendSignal(DBDICT_REF, GSN_CREATE_TABLE_REQ,
      signal, CreateTableReq::SignalLength, JBB, lsPtr, 1);
}

void
Dbdict::createIndex_fromCreateTable(Signal* signal, OpCreateIndexPtr opPtr)
{
  jam();
  if (opPtr.p->hasError()) {
    jam();
    opPtr.p->m_requestType = CreateIndxReq::RT_DICT_ABORT;
    createIndex_sendSlaveReq(signal, opPtr);
    return;
  }
  if (! opPtr.p->m_request.getOnline()) {
    jam();
    opPtr.p->m_requestType = CreateIndxReq::RT_DICT_COMMIT;
    createIndex_sendSlaveReq(signal, opPtr);
    return;
  }
  createIndex_toAlterIndex(signal, opPtr);
}

void
Dbdict::createIndex_toAlterIndex(Signal* signal, OpCreateIndexPtr opPtr)
{
  jam();
  AlterIndxReq* const req = (AlterIndxReq*)signal->getDataPtrSend();
  req->setUserRef(reference());
  req->setConnectionPtr(opPtr.p->key);
  req->setRequestType(AlterIndxReq::RT_CREATE_INDEX);
  req->addRequestFlag(opPtr.p->m_requestFlag);
  req->setTableId(opPtr.p->m_request.getTableId());
  req->setIndexId(opPtr.p->m_request.getIndexId());
  req->setIndexVersion(opPtr.p->m_request.getIndexVersion());
  req->setOnline(true);
  sendSignal(reference(), GSN_ALTER_INDX_REQ,
      signal, AlterIndxReq::SignalLength, JBB);
}

void
Dbdict::createIndex_fromAlterIndex(Signal* signal, OpCreateIndexPtr opPtr)
{
  jam();
  if (opPtr.p->hasError()) {
    jam();
    opPtr.p->m_requestType = CreateIndxReq::RT_DICT_ABORT;
    createIndex_sendSlaveReq(signal, opPtr);
    return;
  }
  opPtr.p->m_requestType = CreateIndxReq::RT_DICT_COMMIT;
  createIndex_sendSlaveReq(signal, opPtr);
}

void
Dbdict::createIndex_slaveCommit(Signal* signal, OpCreateIndexPtr opPtr)
{
  jam();
  const Uint32 indexId = opPtr.p->m_request.getIndexId();
  TableRecordPtr indexPtr;
  c_tableRecordPool.getPtr(indexPtr, indexId);
  if (! opPtr.p->m_request.getOnline()) {
    ndbrequire(indexPtr.p->indexState == TableRecord::IS_UNDEFINED);
    indexPtr.p->indexState = TableRecord::IS_OFFLINE;
  } else {
    ndbrequire(indexPtr.p->indexState == TableRecord::IS_ONLINE);
  }
}

void
Dbdict::createIndex_slaveAbort(Signal* signal, OpCreateIndexPtr opPtr)
{
  jam();
  CreateIndxReq* const req = &opPtr.p->m_request;
  const Uint32 indexId = req->getIndexId();
  if (indexId >= c_tableRecordPool.getSize()) {
    jam();
    return;
  }
  TableRecordPtr indexPtr;
  c_tableRecordPool.getPtr(indexPtr, indexId);
  if (! indexPtr.p->isIndex()) {
    jam();
    return;
  }
  indexPtr.p->indexState = TableRecord::IS_BROKEN;
}

void
Dbdict::createIndex_sendSlaveReq(Signal* signal, OpCreateIndexPtr opPtr)
{
  jam();
  CreateIndxReq* const req = (CreateIndxReq*)signal->getDataPtrSend();
  *req = opPtr.p->m_request;
  req->setUserRef(opPtr.p->m_coordinatorRef);
  req->setConnectionPtr(opPtr.p->key);
  req->setRequestType(opPtr.p->m_requestType);
  req->addRequestFlag(opPtr.p->m_requestFlag);
  opPtr.p->m_signalCounter = c_aliveNodes;
  NodeReceiverGroup rg(DBDICT, c_aliveNodes);
  sendSignal(rg, GSN_CREATE_INDX_REQ,
      signal, CreateIndxReq::SignalLength, JBB);
}

void
Dbdict::createIndex_sendReply(Signal* signal, OpCreateIndexPtr opPtr,
    bool toUser)
{
  CreateIndxRef* rep = (CreateIndxRef*)signal->getDataPtrSend();
  Uint32 gsn = GSN_CREATE_INDX_CONF;
  Uint32 length = CreateIndxConf::InternalLength;
  bool sendRef = opPtr.p->hasError();
  if (! toUser) {
    rep->setUserRef(opPtr.p->m_coordinatorRef);
    rep->setConnectionPtr(opPtr.p->key);
    rep->setRequestType(opPtr.p->m_requestType);
    if (opPtr.p->m_requestType == CreateIndxReq::RT_DICT_ABORT)
      sendRef = false;
  } else {
    rep->setUserRef(opPtr.p->m_request.getUserRef());
    rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr());
    rep->setRequestType(opPtr.p->m_request.getRequestType());
    length = CreateIndxConf::SignalLength;
  }
  rep->setTableId(opPtr.p->m_request.getTableId());
  rep->setIndexId(opPtr.p->m_request.getIndexId());
  rep->setIndexVersion(opPtr.p->m_request.getIndexVersion());
  if (sendRef) {
    if (opPtr.p->m_errorNode == 0)
      opPtr.p->m_errorNode = getOwnNodeId();
    rep->setErrorCode(opPtr.p->m_errorCode);
    rep->setErrorLine(opPtr.p->m_errorLine);
    rep->setErrorNode(opPtr.p->m_errorNode);
    gsn = GSN_CREATE_INDX_REF;
    length = CreateIndxRef::SignalLength;
  }
  sendSignal(rep->getUserRef(), gsn, signal, length, JBB);
}

/**
 * MODULE: Drop index.
 *
 * Drop index.  First alters the index offline (i.e.  drops metadata in
 * other blocks) and then drops the index table.
 */

void
Dbdict::execDROP_INDX_REQ(Signal* signal)
{
  jamEntry();
  DropIndxReq* const req = (DropIndxReq*)signal->getDataPtrSend();
  OpDropIndexPtr opPtr;

  int err = DropIndxRef::BadRequestType;
  const Uint32 senderRef = signal->senderBlockRef();
  const DropIndxReq::RequestType requestType = req->getRequestType();
  if (requestType == DropIndxReq::RT_USER) {
    jam();
    if (signal->getLength() == DropIndxReq::SignalLength) {
      jam();
      if (getOwnNodeId() != c_masterNodeId) {
        jam();
        // forward to DICT master
        sendSignal(calcDictBlockRef(c_masterNodeId), GSN_DROP_INDX_REQ,
            signal, signal->getLength(), JBB);
        return;
      }
      // forward initial request plus operation key to all
      Uint32 indexId= req->getIndexId();
      Uint32 indexVersion= req->getIndexVersion();
      TableRecordPtr tmp;
      int res = getMetaTablePtr(tmp, indexId,  indexVersion);
      switch(res){
      case MetaData::InvalidArgument:
	err = DropIndxRef::IndexNotFound;
	goto error;
      case MetaData::TableNotFound:
      case MetaData::InvalidTableVersion:
	err = DropIndxRef::InvalidIndexVersion;
	goto error;
      }

      if (! tmp.p->isIndex()) {
	jam();
	err = DropIndxRef::NotAnIndex;
	goto error;
      }

      if (tmp.p->indexState == TableRecord::IS_DROPPING){
	jam();
	err = DropIndxRef::IndexNotFound;
	goto error;
      }

      tmp.p->indexState = TableRecord::IS_DROPPING;

      req->setOpKey(++c_opRecordSequence);
      NodeReceiverGroup rg(DBDICT, c_aliveNodes);
      sendSignal(rg, GSN_DROP_INDX_REQ,
          signal, DropIndxReq::SignalLength + 1, JBB);
      return;
    }
    // seize operation record
    ndbrequire(signal->getLength() == DropIndxReq::SignalLength + 1);
    const Uint32 opKey = req->getOpKey();
    OpDropIndex opBusy;
    if (! c_opDropIndex.seize(opPtr))
      opPtr.p = &opBusy;
    opPtr.p->save(req);
    opPtr.p->m_coordinatorRef = senderRef;
    opPtr.p->m_isMaster = (senderRef == reference());
    opPtr.p->key = opKey;
    opPtr.p->m_requestType = DropIndxReq::RT_DICT_PREPARE;
    if (opPtr.p == &opBusy) {
      jam();
      opPtr.p->m_errorCode = DropIndxRef::Busy;
      opPtr.p->m_errorLine = __LINE__;
      dropIndex_sendReply(signal, opPtr, opPtr.p->m_isMaster);
      return;
    }
    c_opDropIndex.add(opPtr);
    // master expects to hear from all
    if (opPtr.p->m_isMaster)
      opPtr.p->m_signalCounter = c_aliveNodes;
    dropIndex_slavePrepare(signal, opPtr);
    dropIndex_sendReply(signal, opPtr, false);
    return;
  }
  c_opDropIndex.find(opPtr, req->getConnectionPtr());
  if (! opPtr.isNull()) {
    opPtr.p->m_requestType = requestType;
    if (requestType == DropIndxReq::RT_DICT_COMMIT ||
        requestType == DropIndxReq::RT_DICT_ABORT) {
      jam();
      if (requestType == DropIndxReq::RT_DICT_COMMIT)
        dropIndex_slaveCommit(signal, opPtr);
      else
        dropIndex_slaveAbort(signal, opPtr);
      dropIndex_sendReply(signal, opPtr, false);
      // done in slave
      if (! opPtr.p->m_isMaster)
        c_opDropIndex.release(opPtr);
      return;
    }
  }
error:
  jam();
  // return to sender
  OpDropIndex opBad;
  opPtr.p = &opBad;
  opPtr.p->save(req);
  opPtr.p->m_errorCode = (DropIndxRef::ErrorCode)err;
  opPtr.p->m_errorLine = __LINE__;
  dropIndex_sendReply(signal, opPtr, true);
}

void
Dbdict::execDROP_INDX_CONF(Signal* signal)
{
  jamEntry();
  DropIndxConf* conf = (DropIndxConf*)signal->getDataPtrSend();
  dropIndex_recvReply(signal, conf, 0);
}

void
Dbdict::execDROP_INDX_REF(Signal* signal) 
{
  jamEntry();
  DropIndxRef* ref = (DropIndxRef*)signal->getDataPtrSend();
  dropIndex_recvReply(signal, ref->getConf(), ref);
}

void
Dbdict::dropIndex_recvReply(Signal* signal, const DropIndxConf* conf,
    const DropIndxRef* ref)
{
  jam();
  const Uint32 senderRef = signal->senderBlockRef();
  const DropIndxReq::RequestType requestType = conf->getRequestType();
  const Uint32 key = conf->getConnectionPtr();
  if (requestType == DropIndxReq::RT_TC) {
    jam();
    // part of alter index operation
    OpAlterIndexPtr opPtr;
    c_opAlterIndex.find(opPtr, key);
    ndbrequire(! opPtr.isNull());
    opPtr.p->setError(ref);
    alterIndex_fromDropTc(signal, opPtr);
    return;
  }
  OpDropIndexPtr opPtr;
  c_opDropIndex.find(opPtr, key);
  ndbrequire(! opPtr.isNull());
  ndbrequire(opPtr.p->m_isMaster);
  ndbrequire(opPtr.p->m_requestType == requestType);
  opPtr.p->setError(ref);
  opPtr.p->m_signalCounter.clearWaitingFor(refToNode(senderRef));
  if (! opPtr.p->m_signalCounter.done()) {
    jam();
    return;
  }
  if (requestType == DropIndxReq::RT_DICT_COMMIT ||
      requestType == DropIndxReq::RT_DICT_ABORT) {
    jam();
    // send reply to user
    dropIndex_sendReply(signal, opPtr, true);
    c_opDropIndex.release(opPtr);
    return;
  }
  if (opPtr.p->hasError()) {
    jam();
    opPtr.p->m_requestType = DropIndxReq::RT_DICT_ABORT;
    dropIndex_sendSlaveReq(signal, opPtr);
    return;
  }
  if (requestType == DropIndxReq::RT_DICT_PREPARE) {
    jam();
    // start alter offline
    dropIndex_toAlterIndex(signal, opPtr);
    return;
  }
  ndbrequire(false);
}

void
Dbdict::dropIndex_slavePrepare(Signal* signal, OpDropIndexPtr opPtr)
{
  jam();
  DropIndxReq* const req = &opPtr.p->m_request;
  // check index exists
  TableRecordPtr indexPtr;
  if (! (req->getIndexId() < c_tableRecordPool.getSize())) {
    jam();
    opPtr.p->m_errorCode = DropIndxRef::IndexNotFound;
    opPtr.p->m_errorLine = __LINE__;
    return;
  }
  c_tableRecordPool.getPtr(indexPtr, req->getIndexId());
  if (indexPtr.p->tabState != TableRecord::DEFINED) {
    jam();
    opPtr.p->m_errorCode = DropIndxRef::IndexNotFound;
    opPtr.p->m_errorLine = __LINE__;
    return;
  }
  if (! indexPtr.p->isIndex()) {
    jam();
    opPtr.p->m_errorCode = DropIndxRef::NotAnIndex;
    opPtr.p->m_errorLine = __LINE__;
    return;
  }
  // ignore incoming primary table id
  req->setTableId(indexPtr.p->primaryTableId);
}

void
Dbdict::dropIndex_toAlterIndex(Signal* signal, OpDropIndexPtr opPtr)
{
  jam();
  AlterIndxReq* const req = (AlterIndxReq*)signal->getDataPtrSend();
  req->setUserRef(reference());
  req->setConnectionPtr(opPtr.p->key);
  req->setRequestType(AlterIndxReq::RT_DROP_INDEX);
  req->addRequestFlag(opPtr.p->m_requestFlag);
  req->setTableId(opPtr.p->m_request.getTableId());
  req->setIndexId(opPtr.p->m_request.getIndexId());
  req->setIndexVersion(opPtr.p->m_request.getIndexVersion());
  req->setOnline(false);
  sendSignal(reference(), GSN_ALTER_INDX_REQ,
      signal, AlterIndxReq::SignalLength, JBB);
}

void
Dbdict::dropIndex_fromAlterIndex(Signal* signal, OpDropIndexPtr opPtr)
{
  jam();
  if (opPtr.p->hasError()) {
    jam();
    opPtr.p->m_requestType = DropIndxReq::RT_DICT_ABORT;
    dropIndex_sendSlaveReq(signal, opPtr);
    return;
  }
  dropIndex_toDropTable(signal, opPtr);
}

void
Dbdict::dropIndex_toDropTable(Signal* signal, OpDropIndexPtr opPtr)
{
  jam();
  DropTableReq* const req = (DropTableReq*)signal->getDataPtrSend();
  req->senderRef = reference();
  req->senderData = opPtr.p->key;
  req->tableId = opPtr.p->m_request.getIndexId();
  req->tableVersion = opPtr.p->m_request.getIndexVersion();
  sendSignal(reference(), GSN_DROP_TABLE_REQ,
      signal,DropTableReq::SignalLength, JBB);
}

void
Dbdict::dropIndex_fromDropTable(Signal* signal, OpDropIndexPtr opPtr)
{
  jam();
  if (opPtr.p->hasError()) {
    jam();
    opPtr.p->m_requestType = DropIndxReq::RT_DICT_ABORT;
    dropIndex_sendSlaveReq(signal, opPtr);
    return;
  }
  opPtr.p->m_requestType = DropIndxReq::RT_DICT_COMMIT;
  dropIndex_sendSlaveReq(signal, opPtr);
}

void
Dbdict::dropIndex_slaveCommit(Signal* signal, OpDropIndexPtr opPtr)
{
  jam();
}

void
Dbdict::dropIndex_slaveAbort(Signal* signal, OpDropIndexPtr opPtr)
{
  jam();
  DropIndxReq* const req = &opPtr.p->m_request;
  const Uint32 indexId = req->getIndexId();
  if (indexId >= c_tableRecordPool.getSize()) {
    jam();
    return;
  }
  TableRecordPtr indexPtr;
  c_tableRecordPool.getPtr(indexPtr, indexId);
  indexPtr.p->indexState = TableRecord::IS_BROKEN;
}

void
Dbdict::dropIndex_sendSlaveReq(Signal* signal, OpDropIndexPtr opPtr)
{
  DropIndxReq* const req = (DropIndxReq*)signal->getDataPtrSend();
  *req = opPtr.p->m_request;
  req->setUserRef(opPtr.p->m_coordinatorRef);
  req->setConnectionPtr(opPtr.p->key);
  req->setRequestType(opPtr.p->m_requestType);
  req->addRequestFlag(opPtr.p->m_requestFlag);
  opPtr.p->m_signalCounter = c_aliveNodes;
  NodeReceiverGroup rg(DBDICT, c_aliveNodes);
  sendSignal(rg, GSN_DROP_INDX_REQ,
      signal, DropIndxReq::SignalLength, JBB);
}

void
Dbdict::dropIndex_sendReply(Signal* signal, OpDropIndexPtr opPtr,
    bool toUser)
{
  DropIndxRef* rep = (DropIndxRef*)signal->getDataPtrSend();
  Uint32 gsn = GSN_DROP_INDX_CONF;
  Uint32 length = DropIndxConf::InternalLength;
  bool sendRef = opPtr.p->hasError();
  if (! toUser) {
    rep->setUserRef(opPtr.p->m_coordinatorRef);
    rep->setConnectionPtr(opPtr.p->key);
    rep->setRequestType(opPtr.p->m_requestType);
    if (opPtr.p->m_requestType == DropIndxReq::RT_DICT_ABORT)
      sendRef = false;
  } else {
    rep->setUserRef(opPtr.p->m_request.getUserRef());
    rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr());
    rep->setRequestType(opPtr.p->m_request.getRequestType());
    length = DropIndxConf::SignalLength;
  }
  rep->setTableId(opPtr.p->m_request.getTableId());
  rep->setIndexId(opPtr.p->m_request.getIndexId());
  rep->setIndexVersion(opPtr.p->m_request.getIndexVersion());
  if (sendRef) {
    if (opPtr.p->m_errorNode == 0)
      opPtr.p->m_errorNode = getOwnNodeId();
    rep->setErrorCode(opPtr.p->m_errorCode);
    rep->setErrorLine(opPtr.p->m_errorLine);
    rep->setErrorNode(opPtr.p->m_errorNode);
    gsn = GSN_DROP_INDX_REF;
    length = DropIndxRef::SignalLength;
  }
  sendSignal(rep->getUserRef(), gsn, signal, length, JBB);
}

/*****************************************************
 *
 * Util signalling
 *
 *****************************************************/

int
Dbdict::sendSignalUtilReq(Callback *pcallback,
			  BlockReference ref, 
			  GlobalSignalNumber gsn, 
			  Signal* signal, 
			  Uint32 length, 
			  JobBufferLevel jbuf,
			  LinearSectionPtr ptr[3],
			  Uint32 noOfSections)
{
  jam();
  EVENT_TRACE;
  OpSignalUtilPtr utilRecPtr;

  // Seize a Util Send record
  if (!c_opSignalUtil.seize(utilRecPtr)) {
    // Failed to allocate util record
    return -1;
  }
  utilRecPtr.p->m_callback = *pcallback;

  // should work for all util signal classes
  UtilPrepareReq *req = (UtilPrepareReq*)signal->getDataPtrSend();
  utilRecPtr.p->m_userData = req->getSenderData();
  req->setSenderData(utilRecPtr.i);

  if (ptr) {
    jam();
    sendSignal(ref, gsn, signal, length, jbuf, ptr, noOfSections);
  } else {
    jam();
    sendSignal(ref, gsn, signal, length, jbuf);
  }

  return 0;
}

int
Dbdict::recvSignalUtilReq(Signal* signal, Uint32 returnCode)
{
  jam();
  EVENT_TRACE;
  UtilPrepareConf * const req = (UtilPrepareConf*)signal->getDataPtr();
  OpSignalUtilPtr utilRecPtr;
  utilRecPtr.i = req->getSenderData();
  if ((utilRecPtr.p = c_opSignalUtil.getPtr(utilRecPtr.i)) == NULL) {
    jam();
    return -1;
  }

  req->setSenderData(utilRecPtr.p->m_userData);
  Callback c = utilRecPtr.p->m_callback;
  c_opSignalUtil.release(utilRecPtr);

  execute(signal, c, returnCode);
  return 0;
}

void Dbdict::execUTIL_PREPARE_CONF(Signal *signal)
{
  jamEntry();
  EVENT_TRACE;
  ndbrequire(recvSignalUtilReq(signal, 0) == 0);
}

void
Dbdict::execUTIL_PREPARE_REF(Signal *signal)
{
  jamEntry();
  EVENT_TRACE;
  ndbrequire(recvSignalUtilReq(signal, 1) == 0);
}

void Dbdict::execUTIL_EXECUTE_CONF(Signal *signal)
{
  jamEntry();
  EVENT_TRACE;
   ndbrequire(recvSignalUtilReq(signal, 0) == 0);
}

void Dbdict::execUTIL_EXECUTE_REF(Signal *signal)
{
  jamEntry();
  EVENT_TRACE;

#ifdef EVENT_DEBUG
  UtilExecuteRef * ref = (UtilExecuteRef *)signal->getDataPtrSend();

  ndbout_c("execUTIL_EXECUTE_REF");
  ndbout_c("senderData %u",ref->getSenderData());
  ndbout_c("errorCode %u",ref->getErrorCode());
  ndbout_c("TCErrorCode %u",ref->getTCErrorCode());
#endif
  
  ndbrequire(recvSignalUtilReq(signal, 1) == 0);
}
void Dbdict::execUTIL_RELEASE_CONF(Signal *signal)
{
  jamEntry();
  EVENT_TRACE;
  ndbrequire(false);
  ndbrequire(recvSignalUtilReq(signal, 0) == 0);
}
void Dbdict::execUTIL_RELEASE_REF(Signal *signal)
{
  jamEntry();
  EVENT_TRACE;
  ndbrequire(false);
  ndbrequire(recvSignalUtilReq(signal, 1) == 0);
}

/**
 * MODULE: Create event
 *
 * Create event in DICT.
 * 
 *
 * Request type in CREATE_EVNT signals:
 *
 * Signalflow see Dbdict.txt
 *
 */

/*****************************************************************
 *
 * Systable stuff
 *
 */

const Uint32 Dbdict::sysTab_NDBEVENTS_0_szs[EVENT_SYSTEM_TABLE_LENGTH] = {
  sizeof(((sysTab_NDBEVENTS_0*)0)->NAME),
  sizeof(((sysTab_NDBEVENTS_0*)0)->EVENT_TYPE),
  sizeof(((sysTab_NDBEVENTS_0*)0)->TABLE_NAME),
  sizeof(((sysTab_NDBEVENTS_0*)0)->ATTRIBUTE_MASK),
  sizeof(((sysTab_NDBEVENTS_0*)0)->SUBID),
  sizeof(((sysTab_NDBEVENTS_0*)0)->SUBKEY)
};

void
Dbdict::prepareTransactionEventSysTable (Callback *pcallback,
					 Signal* signal,
					 Uint32 senderData,
					 UtilPrepareReq::OperationTypeValue prepReq)
{
  // find table id for event system table
  TableRecord keyRecord;
  strcpy(keyRecord.tableName, EVENT_SYSTEM_TABLE_NAME);

  TableRecordPtr tablePtr;
  c_tableRecordHash.find(tablePtr, keyRecord);
  
  ndbrequire(tablePtr.i != RNIL); // system table must exist

  Uint32 tableId = tablePtr.p->tableId; /* System table */
  Uint32 noAttr = tablePtr.p->noOfAttributes;
  ndbrequire(noAttr == EVENT_SYSTEM_TABLE_LENGTH);

  switch (prepReq) {
  case UtilPrepareReq::Update:
  case UtilPrepareReq::Insert:
  case UtilPrepareReq::Write:
  case UtilPrepareReq::Read:
    jam();
    break;
  case UtilPrepareReq::Delete:
    jam();
    noAttr = 1; // only involves Primary key which should be the first
    break;
  }
  prepareUtilTransaction(pcallback, signal, senderData, tableId, NULL,
		      prepReq, noAttr, NULL, NULL);
}

void
Dbdict::prepareUtilTransaction(Callback *pcallback,
			       Signal* signal,
			       Uint32 senderData,
			       Uint32 tableId,
			       const char* tableName,
			       UtilPrepareReq::OperationTypeValue prepReq,
			       Uint32 noAttr,
			       Uint32 attrIds[],
			       const char *attrNames[])
{
  jam();
  EVENT_TRACE;

  UtilPrepareReq * utilPrepareReq = 
    (UtilPrepareReq *)signal->getDataPtrSend();
  
  utilPrepareReq->setSenderRef(reference());
  utilPrepareReq->setSenderData(senderData);

  const Uint32 pageSizeInWords = 128;
  Uint32 propPage[pageSizeInWords];
  LinearWriter w(&propPage[0],128);
  w.first();
  w.add(UtilPrepareReq::NoOfOperations, 1);
  w.add(UtilPrepareReq::OperationType, prepReq);
  if (tableName) {
    jam();
    w.add(UtilPrepareReq::TableName, tableName);
  } else {
    jam();
    w.add(UtilPrepareReq::TableId, tableId);
  }
  for(Uint32 i = 0; i < noAttr; i++)
    if (tableName) {
      jam();
      w.add(UtilPrepareReq::AttributeName, attrNames[i]);
    } else {
      if (attrIds) {
	jam();
	w.add(UtilPrepareReq::AttributeId, attrIds[i]);
      } else {
	jam();
	w.add(UtilPrepareReq::AttributeId, i);
      }
    }
#ifdef EVENT_DEBUG
  // Debugging
  SimplePropertiesLinearReader reader(propPage, w.getWordsUsed());
  printf("Dict::prepareInsertTransactions: Sent SimpleProperties:\n");
  reader.printAll(ndbout);
#endif

  struct LinearSectionPtr sectionsPtr[UtilPrepareReq::NoOfSections];
  sectionsPtr[UtilPrepareReq::PROPERTIES_SECTION].p = propPage;
  sectionsPtr[UtilPrepareReq::PROPERTIES_SECTION].sz = w.getWordsUsed();

  sendSignalUtilReq(pcallback, DBUTIL_REF, GSN_UTIL_PREPARE_REQ, signal,
		    UtilPrepareReq::SignalLength, JBB, 
		    sectionsPtr, UtilPrepareReq::NoOfSections);
}

/*****************************************************************
 *
 * CREATE_EVNT_REQ has three types RT_CREATE, RT_GET (from user)
 * and RT_DICT_AFTER_GET send from master DICT to slaves
 *
 * This function just dscpaches these to
 *
 * createEvent_RT_USER_CREATE
 * createEvent_RT_USER_GET
 * createEvent_RT_DICT_AFTER_GET
 *
 * repectively
 *
 */

void
Dbdict::execCREATE_EVNT_REQ(Signal* signal)
{
  jamEntry();

#if 0
  {
    SafeCounterHandle handle;
    {
      SafeCounter tmp(c_counterMgr, handle);
      tmp.init<CreateEvntRef>(CMVMI, GSN_DUMP_STATE_ORD, /* senderData */ 13);
      tmp.clearWaitingFor();
      tmp.setWaitingFor(3);
      ndbrequire(!tmp.done());
      ndbout_c("Allocted");
    }
    ndbrequire(!handle.done());
    {
      SafeCounter tmp(c_counterMgr, handle);
      tmp.clearWaitingFor(3);
      ndbrequire(tmp.done());
      ndbout_c("Deallocted");
    }
    ndbrequire(handle.done());
  }
  {
    NodeBitmask nodes;
    nodes.clear();

    nodes.set(2);
    nodes.set(3);
    nodes.set(4);
    nodes.set(5);

    {
      Uint32 i = 0;
      while((i = nodes.find(i)) != NodeBitmask::NotFound){
	ndbout_c("1 Node id = %u", i);
	i++;
      }
    }

    NodeReceiverGroup rg(DBDICT, nodes);
    RequestTracker rt2;
    ndbrequire(rt2.done());
    ndbrequire(!rt2.hasRef());
    ndbrequire(!rt2.hasConf());
    rt2.init<CreateEvntRef>(c_counterMgr, rg, GSN_CREATE_EVNT_REF, 13);

    RequestTracker rt3;
    rt3.init<CreateEvntRef>(c_counterMgr, rg, GSN_CREATE_EVNT_REF, 13);

    ndbrequire(!rt2.done());
    ndbrequire(!rt3.done());

    rt2.reportRef(c_counterMgr, 2);
    rt3.reportConf(c_counterMgr, 2);

    ndbrequire(!rt2.done());
    ndbrequire(!rt3.done());

    rt2.reportConf(c_counterMgr, 3);
    rt3.reportConf(c_counterMgr, 3);

    ndbrequire(!rt2.done());
    ndbrequire(!rt3.done());

    rt2.reportConf(c_counterMgr, 4);
    rt3.reportConf(c_counterMgr, 4);

    ndbrequire(!rt2.done());
    ndbrequire(!rt3.done());

    rt2.reportConf(c_counterMgr, 5);
    rt3.reportConf(c_counterMgr, 5);

    ndbrequire(rt2.done());
    ndbrequire(rt3.done());
  }
#endif

  if (! assembleFragments(signal)) {
    jam();
    return;
  }

  CreateEvntReq *req = (CreateEvntReq*)signal->getDataPtr();
  const CreateEvntReq::RequestType requestType = req->getRequestType();
  const Uint32                     requestFlag = req->getRequestFlag();

  OpCreateEventPtr evntRecPtr;
  // Seize a Create Event record
  if (!c_opCreateEvent.seize(evntRecPtr)) {
    // Failed to allocate event record
    jam();
    releaseSections(signal);

    CreateEvntRef * ret = (CreateEvntRef *)signal->getDataPtrSend();
    ret->senderRef = reference();
    ret->setErrorCode(CreateEvntRef::SeizeError);
    ret->setErrorLine(__LINE__);
    ret->setErrorNode(reference());
    sendSignal(signal->senderBlockRef(), GSN_CREATE_EVNT_REF, signal,
	       CreateEvntRef::SignalLength, JBB);
    return;
  }

#ifdef EVENT_DEBUG
  ndbout_c("DBDICT::execCREATE_EVNT_REQ from %u evntRecId = (%d)", refToNode(signal->getSendersBlockRef()), evntRecPtr.i);
#endif
  
  ndbrequire(req->getUserRef() == signal->getSendersBlockRef());

  evntRecPtr.p->init(req,this);

  if (requestFlag & (Uint32)CreateEvntReq::RT_DICT_AFTER_GET) {
    jam();
    EVENT_TRACE;
    createEvent_RT_DICT_AFTER_GET(signal, evntRecPtr);
    return;
  }
  if (requestType == CreateEvntReq::RT_USER_GET) {
    jam();
    EVENT_TRACE;
    createEvent_RT_USER_GET(signal, evntRecPtr);
    return;
  }
  if (requestType == CreateEvntReq::RT_USER_CREATE) {
    jam();
    EVENT_TRACE;
    createEvent_RT_USER_CREATE(signal, evntRecPtr);
    return;
  }

#ifdef EVENT_DEBUG
  ndbout << "Dbdict.cpp: Dbdict::execCREATE_EVNT_REQ other" << endl;
#endif
  jam();
  releaseSections(signal);
    
  evntRecPtr.p->m_errorCode = CreateEvntRef::Undefined;
  evntRecPtr.p->m_errorLine = __LINE__;
  evntRecPtr.p->m_errorNode = reference();
  
  createEvent_sendReply(signal, evntRecPtr);
}

/********************************************************************
 *
 * Event creation
 *
 *****************************************************************/

void
Dbdict::createEvent_RT_USER_CREATE(Signal* signal, OpCreateEventPtr evntRecPtr){
  jam();
  evntRecPtr.p->m_request.setUserRef(signal->senderBlockRef());

#ifdef EVENT_DEBUG
  ndbout << "Dbdict.cpp: Dbdict::execCREATE_EVNT_REQ RT_USER" << endl;
  char buf[128] = {0};
  AttributeMask mask = evntRecPtr.p->m_request.getAttrListBitmask(); 
  mask.getText(buf);
  ndbout_c("mask = %s", buf);
#endif

  // Interpret the long signal

  SegmentedSectionPtr ssPtr;
  // save name and event properties
  signal->getSection(ssPtr, CreateEvntReq::EVENT_NAME_SECTION);

  SimplePropertiesSectionReader r0(ssPtr, getSectionSegmentPool());
#ifdef EVENT_DEBUG
  r0.printAll(ndbout);
#endif
    // event name
  if ((!r0.first()) ||
      (r0.getValueType() != SimpleProperties::StringValue) ||
      (r0.getValueLen() <= 0)) {
    jam();
    releaseSections(signal);

    evntRecPtr.p->m_errorCode = CreateEvntRef::Undefined;
    evntRecPtr.p->m_errorLine = __LINE__;
    evntRecPtr.p->m_errorNode = reference();

    createEvent_sendReply(signal, evntRecPtr);
    return;
  }
  r0.getString(evntRecPtr.p->m_eventRec.NAME);
  {
    int len = strlen(evntRecPtr.p->m_eventRec.NAME);
    memset(evntRecPtr.p->m_eventRec.NAME+len, 0, MAX_TAB_NAME_SIZE-len);
#ifdef EVENT_DEBUG
    printf("CreateEvntReq::RT_USER_CREATE; EventName %s, len %u\n",
	   evntRecPtr.p->m_eventRec.NAME, len);
    for(int i = 0; i < MAX_TAB_NAME_SIZE/4; i++)
      printf("H'%.8x ", ((Uint32*)evntRecPtr.p->m_eventRec.NAME)[i]);
    printf("\n");
#endif
  }
  // table name
  if ((!r0.next()) ||
      (r0.getValueType() != SimpleProperties::StringValue) ||
      (r0.getValueLen() <= 0)) {
    jam();
    releaseSections(signal);
    
    evntRecPtr.p->m_errorCode = CreateEvntRef::Undefined;
    evntRecPtr.p->m_errorLine = __LINE__;
    evntRecPtr.p->m_errorNode = reference();
    
    createEvent_sendReply(signal, evntRecPtr);
    return;
  }
  r0.getString(evntRecPtr.p->m_eventRec.TABLE_NAME);
  {
    int len = strlen(evntRecPtr.p->m_eventRec.TABLE_NAME);
    memset(evntRecPtr.p->m_eventRec.TABLE_NAME+len, 0, MAX_TAB_NAME_SIZE-len);
  }
  
#ifdef EVENT_DEBUG
  ndbout_c("event name: %s",evntRecPtr.p->m_eventRec.NAME);
  ndbout_c("table name: %s",evntRecPtr.p->m_eventRec.TABLE_NAME);
#endif
  
  releaseSections(signal);
  
  // Send request to SUMA

  CreateSubscriptionIdReq * sumaIdReq =
    (CreateSubscriptionIdReq *)signal->getDataPtrSend();
  
  // make sure we save the original sender for later
  sumaIdReq->senderData = evntRecPtr.i;
#ifdef EVENT_DEBUG
  ndbout << "sumaIdReq->senderData = " << sumaIdReq->senderData << endl;
#endif
  sendSignal(SUMA_REF, GSN_CREATE_SUBID_REQ, signal, 
	     CreateSubscriptionIdReq::SignalLength, JBB);
  // we should now return in either execCREATE_SUBID_CONF
  // or execCREATE_SUBID_REF
}

void Dbdict::execCREATE_SUBID_REF(Signal* signal)
{
  jamEntry();      
  EVENT_TRACE;
  CreateSubscriptionIdRef * const ref =
    (CreateSubscriptionIdRef *)signal->getDataPtr();
  OpCreateEventPtr evntRecPtr;

  evntRecPtr.i = ref->senderData;
  ndbrequire((evntRecPtr.p = c_opCreateEvent.getPtr(evntRecPtr.i)) != NULL);

  evntRecPtr.p->m_errorCode = CreateEvntRef::Undefined;
  evntRecPtr.p->m_errorLine = __LINE__;
  evntRecPtr.p->m_errorNode = reference();

  createEvent_sendReply(signal, evntRecPtr);
}

void Dbdict::execCREATE_SUBID_CONF(Signal* signal)
{
  jamEntry();
  EVENT_TRACE;

  CreateSubscriptionIdConf const * sumaIdConf =
    (CreateSubscriptionIdConf *)signal->getDataPtr();

  Uint32 evntRecId = sumaIdConf->senderData;
  OpCreateEvent *evntRec;

  ndbrequire((evntRec = c_opCreateEvent.getPtr(evntRecId)) != NULL);

  evntRec->m_request.setEventId(sumaIdConf->subscriptionId);
  evntRec->m_request.setEventKey(sumaIdConf->subscriptionKey);

  releaseSections(signal);

  Callback c = { safe_cast(&Dbdict::createEventUTIL_PREPARE), 0 };

  prepareTransactionEventSysTable(&c, signal, evntRecId,
				  UtilPrepareReq::Insert);
}

void
Dbdict::createEventComplete_RT_USER_CREATE(Signal* signal,
					   OpCreateEventPtr evntRecPtr){
  jam();
  createEvent_sendReply(signal, evntRecPtr);
}

/*********************************************************************
 *
 * UTIL_PREPARE, UTIL_EXECUTE
 *
 * insert or read systable NDB$EVENTS_0
 */

void interpretUtilPrepareErrorCode(UtilPrepareRef::ErrorCode errorCode,
				   bool& temporary, Uint32& line)
{
  switch (errorCode) {
  case UtilPrepareRef::NO_ERROR:
    jam();
    line = __LINE__;
    EVENT_TRACE;
    break;
  case UtilPrepareRef::PREPARE_SEIZE_ERROR:
    jam();
    temporary = true;
    line = __LINE__;
    EVENT_TRACE;
    break;
  case UtilPrepareRef::PREPARE_PAGES_SEIZE_ERROR:
    jam();
    line = __LINE__;
    EVENT_TRACE;
    break;
  case UtilPrepareRef::PREPARED_OPERATION_SEIZE_ERROR:
    jam();
    line = __LINE__;
    EVENT_TRACE;
    break;
  case UtilPrepareRef::DICT_TAB_INFO_ERROR:
    jam();
    line = __LINE__;
    EVENT_TRACE;
    break;
  case UtilPrepareRef::MISSING_PROPERTIES_SECTION:
    jam();
    line = __LINE__;
    EVENT_TRACE;
    break;
  default:
    jam();
    line = __LINE__;
    EVENT_TRACE;
    break;
  }
}

void 
Dbdict::createEventUTIL_PREPARE(Signal* signal,
				Uint32 callbackData,
				Uint32 returnCode)
{
  jam();
  EVENT_TRACE;
  if (returnCode == 0) {
    UtilPrepareConf* const req = (UtilPrepareConf*)signal->getDataPtr();
    OpCreateEventPtr evntRecPtr;
    jam();
    evntRecPtr.i = req->getSenderData();
    const Uint32 prepareId = req->getPrepareId();
    
    ndbrequire((evntRecPtr.p = c_opCreateEvent.getPtr(evntRecPtr.i)) != NULL);
    
    Callback c = { safe_cast(&Dbdict::createEventUTIL_EXECUTE), 0 };

    switch (evntRecPtr.p->m_requestType) {
    case CreateEvntReq::RT_USER_GET:
#ifdef EVENT_DEBUG
      printf("get type = %d\n", CreateEvntReq::RT_USER_GET);
#endif
      jam();
      executeTransEventSysTable(&c, signal,
				evntRecPtr.i, evntRecPtr.p->m_eventRec,
				prepareId, UtilPrepareReq::Read);
      break;
    case CreateEvntReq::RT_USER_CREATE:
#ifdef EVENT_DEBUG
      printf("create type = %d\n", CreateEvntReq::RT_USER_CREATE);
#endif
      {
	evntRecPtr.p->m_eventRec.EVENT_TYPE = evntRecPtr.p->m_request.getEventType();
	AttributeMask m = evntRecPtr.p->m_request.getAttrListBitmask();
	memcpy(evntRecPtr.p->m_eventRec.ATTRIBUTE_MASK, &m,
	       sizeof(evntRecPtr.p->m_eventRec.ATTRIBUTE_MASK));
	evntRecPtr.p->m_eventRec.SUBID  = evntRecPtr.p->m_request.getEventId();
	evntRecPtr.p->m_eventRec.SUBKEY = evntRecPtr.p->m_request.getEventKey();
      }
      jam();
      executeTransEventSysTable(&c, signal,
				evntRecPtr.i, evntRecPtr.p->m_eventRec,
				prepareId, UtilPrepareReq::Insert);
      break;
    default:
#ifdef EVENT_DEBUG
      printf("type = %d\n", evntRecPtr.p->m_requestType);
      printf("bet type = %d\n", CreateEvntReq::RT_USER_GET);
      printf("create type = %d\n", CreateEvntReq::RT_USER_CREATE);
#endif
      ndbrequire(false);
    }
  } else { // returnCode != 0
    UtilPrepareRef* const ref = (UtilPrepareRef*)signal->getDataPtr();

    const UtilPrepareRef::ErrorCode errorCode =
      (UtilPrepareRef::ErrorCode)ref->getErrorCode();

    OpCreateEventPtr evntRecPtr;
    evntRecPtr.i = ref->getSenderData();
    ndbrequire((evntRecPtr.p = c_opCreateEvent.getPtr(evntRecPtr.i)) != NULL);

    bool temporary = false;
    interpretUtilPrepareErrorCode(errorCode,
				  temporary, evntRecPtr.p->m_errorLine);
    if (temporary) {
      evntRecPtr.p->m_errorCode =
	CreateEvntRef::makeTemporary(CreateEvntRef::Undefined);
    }

    if (evntRecPtr.p->m_errorCode == 0) {
      evntRecPtr.p->m_errorCode = CreateEvntRef::Undefined;
    }
    evntRecPtr.p->m_errorNode = reference();

    createEvent_sendReply(signal, evntRecPtr);
  }
}

void Dbdict::executeTransEventSysTable(Callback *pcallback, Signal *signal,
				       const Uint32 ptrI,
				       sysTab_NDBEVENTS_0& m_eventRec,
				       const Uint32 prepareId,
				       UtilPrepareReq::OperationTypeValue prepReq)
{
  jam();
  const Uint32 noAttr = EVENT_SYSTEM_TABLE_LENGTH;
  Uint32 total_len = 0;

  Uint32* attrHdr = signal->theData + 25;
  Uint32* attrPtr = attrHdr;

  Uint32 id=0;
  // attribute 0 event name: Primary Key
  {
    AttributeHeader::init(attrPtr, id, sysTab_NDBEVENTS_0_szs[id]/4);
    total_len += sysTab_NDBEVENTS_0_szs[id];
    attrPtr++; id++;
  }

  switch (prepReq) {
  case UtilPrepareReq::Read:
    jam();
    EVENT_TRACE;
    // no more
    while ( id < noAttr )
      AttributeHeader::init(attrPtr++, id++, 0);
    ndbrequire(id == (Uint32) noAttr);
    break;
  case UtilPrepareReq::Insert:
    jam();
    EVENT_TRACE;
    while ( id < noAttr ) {
      AttributeHeader::init(attrPtr, id, sysTab_NDBEVENTS_0_szs[id]/4);
      total_len += sysTab_NDBEVENTS_0_szs[id];
      attrPtr++; id++;
    }
    ndbrequire(id == (Uint32) noAttr);
    break;
  case UtilPrepareReq::Delete:
    ndbrequire(id == 1);
    break;
  default:
    ndbrequire(false);
  }
    
  LinearSectionPtr headerPtr;
  LinearSectionPtr dataPtr;
    
  headerPtr.p = attrHdr;
  headerPtr.sz = noAttr;
    
  dataPtr.p = (Uint32*)&m_eventRec;
  dataPtr.sz = total_len/4;

  ndbrequire((total_len == sysTab_NDBEVENTS_0_szs[0]) ||
	     (total_len == sizeof(sysTab_NDBEVENTS_0)));

#if 0
    printf("Header size %u\n", headerPtr.sz);
    for(int i = 0; i < (int)headerPtr.sz; i++)
      printf("H'%.8x ", attrHdr[i]);
    printf("\n");
    
    printf("Data size %u\n", dataPtr.sz);
    for(int i = 0; i < (int)dataPtr.sz; i++)
      printf("H'%.8x ", dataPage[i]);
    printf("\n");
#endif

  executeTransaction(pcallback, signal, 
		     ptrI,
		     prepareId,
		     id,
		     headerPtr,
		     dataPtr);
}

void Dbdict::executeTransaction(Callback *pcallback,
				Signal* signal, 
				Uint32 senderData,
				Uint32 prepareId,
				Uint32 noAttr,
				LinearSectionPtr headerPtr,
				LinearSectionPtr dataPtr)
{
  jam();
  EVENT_TRACE;

  UtilExecuteReq * utilExecuteReq = 
    (UtilExecuteReq *)signal->getDataPtrSend();

  utilExecuteReq->setSenderRef(reference());
  utilExecuteReq->setSenderData(senderData);
  utilExecuteReq->setPrepareId(prepareId);
  utilExecuteReq->setReleaseFlag(); // must be done after setting prepareId

#if 0
  printf("Header size %u\n", headerPtr.sz);
  for(int i = 0; i < (int)headerPtr.sz; i++)
    printf("H'%.8x ", headerBuffer[i]);
  printf("\n");
  
  printf("Data size %u\n", dataPtr.sz);
  for(int i = 0; i < (int)dataPtr.sz; i++)
    printf("H'%.8x ", dataBuffer[i]);
  printf("\n");
#endif

  struct LinearSectionPtr sectionsPtr[UtilExecuteReq::NoOfSections];
  sectionsPtr[UtilExecuteReq::HEADER_SECTION].p = headerPtr.p;
  sectionsPtr[UtilExecuteReq::HEADER_SECTION].sz = noAttr;
  sectionsPtr[UtilExecuteReq::DATA_SECTION].p = dataPtr.p;
  sectionsPtr[UtilExecuteReq::DATA_SECTION].sz = dataPtr.sz;

  sendSignalUtilReq(pcallback, DBUTIL_REF, GSN_UTIL_EXECUTE_REQ, signal,
		    UtilExecuteReq::SignalLength, JBB,
		    sectionsPtr, UtilExecuteReq::NoOfSections);
}

void Dbdict::parseReadEventSys(Signal* signal, sysTab_NDBEVENTS_0& m_eventRec)
{
  SegmentedSectionPtr headerPtr, dataPtr;
  jam();
  signal->getSection(headerPtr, UtilExecuteReq::HEADER_SECTION);
  SectionReader headerReader(headerPtr, getSectionSegmentPool());
      
  signal->getSection(dataPtr, UtilExecuteReq::DATA_SECTION);
  SectionReader dataReader(dataPtr, getSectionSegmentPool());
  
  AttributeHeader header;
  Uint32 *dst = (Uint32*)&m_eventRec;

  for (int i = 0; i < EVENT_SYSTEM_TABLE_LENGTH; i++) {
    headerReader.getWord((Uint32 *)&header);
    int sz = header.getDataSize();
    for (int i=0; i < sz; i++)
      dataReader.getWord(dst++);
  }

  ndbrequire( ((char*)dst-(char*)&m_eventRec) == sizeof(m_eventRec) );

  releaseSections(signal);
}
    
void Dbdict::createEventUTIL_EXECUTE(Signal *signal, 
				     Uint32 callbackData,
				     Uint32 returnCode)
{
  jam();
  EVENT_TRACE;
  if (returnCode == 0) {
    // Entry into system table all set
    UtilExecuteConf* const conf = (UtilExecuteConf*)signal->getDataPtr();
    jam();
    OpCreateEventPtr evntRecPtr;
    evntRecPtr.i = conf->getSenderData();
    
    ndbrequire((evntRecPtr.p = c_opCreateEvent.getPtr(evntRecPtr.i)) != NULL);
    OpCreateEvent *evntRec = evntRecPtr.p;
    
    switch (evntRec->m_requestType) {
    case CreateEvntReq::RT_USER_GET: {
#ifdef EVENT_DEBUG
      printf("get type = %d\n", CreateEvntReq::RT_USER_GET);
#endif
      parseReadEventSys(signal, evntRecPtr.p->m_eventRec);

      evntRec->m_request.setEventType(evntRecPtr.p->m_eventRec.EVENT_TYPE);
      evntRec->m_request.setAttrListBitmask(*(AttributeMask*)evntRecPtr.p->m_eventRec.ATTRIBUTE_MASK);
      evntRec->m_request.setEventId(evntRecPtr.p->m_eventRec.SUBID);
      evntRec->m_request.setEventKey(evntRecPtr.p->m_eventRec.SUBKEY);

#ifdef EVENT_DEBUG
      printf("EventName: %s\n", evntRec->m_eventRec.NAME);
      printf("TableName: %s\n", evntRec->m_eventRec.TABLE_NAME);
#endif
      
      // find table id for event table
      TableRecord keyRecord;
      strcpy(keyRecord.tableName, evntRecPtr.p->m_eventRec.TABLE_NAME);
      
      TableRecordPtr tablePtr;
      c_tableRecordHash.find(tablePtr, keyRecord);
      
      if (tablePtr.i == RNIL) {
	jam();
	evntRecPtr.p->m_errorCode = CreateEvntRef::Undefined;
	evntRecPtr.p->m_errorLine = __LINE__;
	evntRecPtr.p->m_errorNode = reference();
	
	createEvent_sendReply(signal, evntRecPtr);
	return;
      }
      
      evntRec->m_request.setTableId(tablePtr.p->tableId);
      
      createEventComplete_RT_USER_GET(signal, evntRecPtr);
      return;
    }
    case CreateEvntReq::RT_USER_CREATE: {
#ifdef EVENT_DEBUG
      printf("create type = %d\n", CreateEvntReq::RT_USER_CREATE);
#endif
      jam();
      createEventComplete_RT_USER_CREATE(signal, evntRecPtr);
      return;
    }
      break;
    default:
      ndbrequire(false);
    }
  } else { // returnCode != 0
    UtilExecuteRef * const ref = (UtilExecuteRef *)signal->getDataPtr();
    OpCreateEventPtr evntRecPtr;
    evntRecPtr.i = ref->getSenderData();
    ndbrequire((evntRecPtr.p = c_opCreateEvent.getPtr(evntRecPtr.i)) != NULL);
    jam();
    evntRecPtr.p->m_errorNode = reference();
    evntRecPtr.p->m_errorLine = __LINE__;

    switch (ref->getErrorCode()) {
    case UtilExecuteRef::TCError:
      switch (ref->getTCErrorCode()) {
      case ZNOT_FOUND:
	jam();
	evntRecPtr.p->m_errorCode = CreateEvntRef::EventNotFound;
	break;
      case ZALREADYEXIST:
	jam();
	evntRecPtr.p->m_errorCode = CreateEvntRef::EventNameExists;
	break;
      default:
	jam();
	evntRecPtr.p->m_errorCode = CreateEvntRef::UndefinedTCError;
	break;
      }
      break;
    default:
      jam();
      evntRecPtr.p->m_errorCode = CreateEvntRef::Undefined;
      break;
    }
    
    createEvent_sendReply(signal, evntRecPtr);
  }
}

/***********************************************************************
 *
 * NdbEventOperation, reading systable, creating event in suma
 *
 */

void
Dbdict::createEvent_RT_USER_GET(Signal* signal, OpCreateEventPtr evntRecPtr){
  jam();
  EVENT_TRACE;
#ifdef EVENT_PH2_DEBUG
  ndbout_c("DBDICT(Coordinator) got GSN_CREATE_EVNT_REQ::RT_USER_GET evntRecPtr.i = (%d), ref = %u", evntRecPtr.i, evntRecPtr.p->m_request.getUserRef());
#endif

  SegmentedSectionPtr ssPtr;

  signal->getSection(ssPtr, 0);

  SimplePropertiesSectionReader r0(ssPtr, getSectionSegmentPool());
#ifdef EVENT_DEBUG
  r0.printAll(ndbout);
#endif
  if ((!r0.first()) ||
      (r0.getValueType() != SimpleProperties::StringValue) ||
      (r0.getValueLen() <= 0)) {
    jam();
    releaseSections(signal);

    evntRecPtr.p->m_errorCode = CreateEvntRef::Undefined;
    evntRecPtr.p->m_errorLine = __LINE__;
    evntRecPtr.p->m_errorNode = reference();

    createEvent_sendReply(signal, evntRecPtr);
    return;
  }

  r0.getString(evntRecPtr.p->m_eventRec.NAME);
  int len = strlen(evntRecPtr.p->m_eventRec.NAME);
  memset(evntRecPtr.p->m_eventRec.NAME+len, 0, MAX_TAB_NAME_SIZE-len);
  
  releaseSections(signal);
  
  Callback c = { safe_cast(&Dbdict::createEventUTIL_PREPARE), 0 };
  
  prepareTransactionEventSysTable(&c, signal, evntRecPtr.i,
				  UtilPrepareReq::Read);
  /* 
   * Will read systable and fill an OpCreateEventPtr
   * and return below
   */
}

void
Dbdict::createEventComplete_RT_USER_GET(Signal* signal,
					OpCreateEventPtr evntRecPtr){
  jam();

  // Send to oneself and the other DICT's
  CreateEvntReq * req = (CreateEvntReq *)signal->getDataPtrSend();
      
  *req = evntRecPtr.p->m_request;
  req->senderRef = reference();
  req->senderData = evntRecPtr.i;
      
  req->addRequestFlag(CreateEvntReq::RT_DICT_AFTER_GET);
      
#ifdef EVENT_PH2_DEBUG
  ndbout_c("DBDICT(Coordinator) sending GSN_CREATE_EVNT_REQ::RT_DICT_AFTER_GET to DBDICT participants evntRecPtr.i = (%d)", evntRecPtr.i);
#endif

  NodeReceiverGroup rg(DBDICT, c_aliveNodes);
  RequestTracker & p = evntRecPtr.p->m_reqTracker;
  p.init<CreateEvntRef>(c_counterMgr, rg, GSN_CREATE_EVNT_REF, evntRecPtr.i);

  sendSignal(rg, GSN_CREATE_EVNT_REQ, signal, CreateEvntReq::SignalLength, JBB);
}

void
Dbdict::createEvent_nodeFailCallback(Signal* signal, Uint32 eventRecPtrI,
				     Uint32 returnCode){
  OpCreateEventPtr evntRecPtr;
  c_opCreateEvent.getPtr(evntRecPtr, eventRecPtrI);
  createEvent_sendReply(signal, evntRecPtr);
}

void Dbdict::execCREATE_EVNT_REF(Signal* signal) 
{
  jamEntry();      
  EVENT_TRACE;
  CreateEvntRef * const ref = (CreateEvntRef *)signal->getDataPtr();
  OpCreateEventPtr evntRecPtr;

  evntRecPtr.i = ref->getUserData();

  ndbrequire((evntRecPtr.p = c_opCreateEvent.getPtr(evntRecPtr.i)) != NULL);

#ifdef EVENT_PH2_DEBUG
  ndbout_c("DBDICT(Coordinator) got GSN_CREATE_EVNT_REF evntRecPtr.i = (%d)", evntRecPtr.i);
#endif

  if (ref->errorCode == CreateEvntRef::NF_FakeErrorREF){
    jam();
    evntRecPtr.p->m_reqTracker.ignoreRef(c_counterMgr, refToNode(ref->senderRef));
  } else {
    jam();
    evntRecPtr.p->m_reqTracker.reportRef(c_counterMgr, refToNode(ref->senderRef));
  }
  createEvent_sendReply(signal, evntRecPtr);

  return;
}

void Dbdict::execCREATE_EVNT_CONF(Signal* signal)
{
  jamEntry();
  EVENT_TRACE;
  CreateEvntConf * const conf = (CreateEvntConf *)signal->getDataPtr();
  OpCreateEventPtr evntRecPtr;

  evntRecPtr.i = conf->getUserData();

  ndbrequire((evntRecPtr.p = c_opCreateEvent.getPtr(evntRecPtr.i)) != NULL);

#ifdef EVENT_PH2_DEBUG
  ndbout_c("DBDICT(Coordinator) got GSN_CREATE_EVNT_CONF evntRecPtr.i = (%d)", evntRecPtr.i);
#endif

  evntRecPtr.p->m_reqTracker.reportConf(c_counterMgr, refToNode(conf->senderRef));

  // we will only have a valid tablename if it the master DICT sending this
  // but that's ok
  LinearSectionPtr ptr[1];
  ptr[0].p = (Uint32 *)evntRecPtr.p->m_eventRec.TABLE_NAME;
  ptr[0].sz =
    (strlen(evntRecPtr.p->m_eventRec.TABLE_NAME)+4)/4; // to make sure we have a null

  createEvent_sendReply(signal, evntRecPtr, ptr, 1);
    
  return;
}

/************************************************
 *
 * Participant stuff
 *
 */

void
Dbdict::createEvent_RT_DICT_AFTER_GET(Signal* signal, OpCreateEventPtr evntRecPtr){
  jam();
  evntRecPtr.p->m_request.setUserRef(signal->senderBlockRef());
  
#ifdef EVENT_PH2_DEBUG
  ndbout_c("DBDICT(Participant) got CREATE_EVNT_REQ::RT_DICT_AFTER_GET evntRecPtr.i = (%d)", evntRecPtr.i);
#endif

  // the signal comes from the DICT block that got the first user request!
  // This code runs on all DICT nodes, including oneself

  // Seize a Create Event record, the Coordinator will now have two seized
  // but that's ok, it's like a recursion

  SubCreateReq * sumaReq = (SubCreateReq *)signal->getDataPtrSend();
  
  sumaReq->subscriberRef    = reference(); // reference to DICT
  sumaReq->subscriberData   = evntRecPtr.i;
  sumaReq->subscriptionId   = evntRecPtr.p->m_request.getEventId();
  sumaReq->subscriptionKey  = evntRecPtr.p->m_request.getEventKey();
  sumaReq->subscriptionType = SubCreateReq::TableEvent;
  sumaReq->tableId          = evntRecPtr.p->m_request.getTableId();
    
#ifdef EVENT_PH2_DEBUG
  ndbout_c("sending GSN_SUB_CREATE_REQ");
#endif

  sendSignal(SUMA_REF, GSN_SUB_CREATE_REQ, signal,
	     SubCreateReq::SignalLength+1 /*to get table Id*/, JBB);
}

void Dbdict::execSUB_CREATE_REF(Signal* signal)
{
  jamEntry();
  EVENT_TRACE;
  SubCreateRef * const ref = (SubCreateRef *)signal->getDataPtr();
  OpCreateEventPtr evntRecPtr;

  evntRecPtr.i = ref->subscriberData;
  ndbrequire((evntRecPtr.p = c_opCreateEvent.getPtr(evntRecPtr.i)) != NULL);

#ifdef EVENT_PH2_DEBUG
  ndbout_c("DBDICT(Participant) got SUB_CREATE_REF evntRecPtr.i = (%d)", evntRecPtr.i);
#endif

  if (ref->err == GrepError::SUBSCRIPTION_ID_NOT_UNIQUE) {
    jam();
#ifdef EVENT_PH2_DEBUG
    ndbout_c("SUBSCRIPTION_ID_NOT_UNIQUE");
#endif
    createEvent_sendReply(signal, evntRecPtr);
    return;
  }

#ifdef EVENT_PH2_DEBUG
    ndbout_c("Other error");
#endif

  evntRecPtr.p->m_errorCode = CreateEvntRef::Undefined;
  evntRecPtr.p->m_errorLine = __LINE__;
  evntRecPtr.p->m_errorNode = reference();

  createEvent_sendReply(signal, evntRecPtr);
}

void Dbdict::execSUB_CREATE_CONF(Signal* signal)
{
  jamEntry();
  EVENT_TRACE;

  SubCreateConf * const sumaConf = (SubCreateConf *)signal->getDataPtr();

  const Uint32 subscriptionId  = sumaConf->subscriptionId;
  const Uint32 subscriptionKey = sumaConf->subscriptionKey;
  const Uint32 evntRecId       = sumaConf->subscriberData;

  OpCreateEvent *evntRec;
  ndbrequire((evntRec = c_opCreateEvent.getPtr(evntRecId)) != NULL);

#ifdef EVENT_PH2_DEBUG
  ndbout_c("DBDICT(Participant) got SUB_CREATE_CONF evntRecPtr.i = (%d)", evntRecId);
#endif

  SubSyncReq *sumaSync = (SubSyncReq *)signal->getDataPtrSend();

  sumaSync->subscriptionId = subscriptionId;
  sumaSync->subscriptionKey = subscriptionKey;
  sumaSync->part = (Uint32) SubscriptionData::MetaData;
  sumaSync->subscriberData = evntRecId;

  sendSignal(SUMA_REF, GSN_SUB_SYNC_REQ, signal,
	     SubSyncReq::SignalLength, JBB);
}

void Dbdict::execSUB_SYNC_REF(Signal* signal)
{
  jamEntry();
  EVENT_TRACE;
  SubSyncRef * const ref = (SubSyncRef *)signal->getDataPtr();
  OpCreateEventPtr evntRecPtr;

  evntRecPtr.i = ref->subscriberData;
  ndbrequire((evntRecPtr.p = c_opCreateEvent.getPtr(evntRecPtr.i)) != NULL);

  evntRecPtr.p->m_errorCode = CreateEvntRef::Undefined;
  evntRecPtr.p->m_errorLine = __LINE__;
  evntRecPtr.p->m_errorNode = reference();

  createEvent_sendReply(signal, evntRecPtr);
}

void Dbdict::execSUB_SYNC_CONF(Signal* signal) 
{
  jamEntry();
  EVENT_TRACE;

  SubSyncConf * const sumaSyncConf = (SubSyncConf *)signal->getDataPtr();

  //  Uint32 subscriptionId = sumaSyncConf->subscriptionId;
  //  Uint32 subscriptionKey = sumaSyncConf->subscriptionKey;
  OpCreateEventPtr evntRecPtr;

  evntRecPtr.i = sumaSyncConf->subscriberData;
  ndbrequire((evntRecPtr.p = c_opCreateEvent.getPtr(evntRecPtr.i)) != NULL);

  ndbrequire(sumaSyncConf->part == (Uint32)SubscriptionData::MetaData);

  createEvent_sendReply(signal, evntRecPtr);
}

/****************************************************
 *
 * common create reply method
 *
 *******************************************************/

void Dbdict::createEvent_sendReply(Signal* signal,
				   OpCreateEventPtr evntRecPtr,
				   LinearSectionPtr *ptr, int noLSP)
{
  jam();
  EVENT_TRACE;

  // check if we're ready to sent reply
  // if we are the master dict we might be waiting for conf/ref

  if (!evntRecPtr.p->m_reqTracker.done()) {
    jam();
    return; // there's more to come
  }

  if (evntRecPtr.p->m_reqTracker.hasRef()) {
    ptr = NULL; // we don't want to return anything if there's an error
    if (!evntRecPtr.p->hasError()) {
      evntRecPtr.p->m_errorCode = CreateEvntRef::Undefined;
      evntRecPtr.p->m_errorLine = __LINE__;
      evntRecPtr.p->m_errorNode = reference();
      jam();
    } else 
      jam();
  }

  // reference to API if master DICT
  // else reference to master DICT
  Uint32 senderRef = evntRecPtr.p->m_request.getUserRef();
  Uint32 signalLength;
  Uint32 gsn;

  if (evntRecPtr.p->hasError()) {
    jam();
    EVENT_TRACE;
    CreateEvntRef * ret = (CreateEvntRef *)signal->getDataPtrSend();
    
    ret->setEventId(evntRecPtr.p->m_request.getEventId());
    ret->setEventKey(evntRecPtr.p->m_request.getEventKey());
    ret->setUserData(evntRecPtr.p->m_request.getUserData());
    ret->senderRef = reference();
    ret->setTableId(evntRecPtr.p->m_request.getTableId());
    ret->setEventType(evntRecPtr.p->m_request.getEventType());
    ret->setRequestType(evntRecPtr.p->m_request.getRequestType());

    ret->setErrorCode(evntRecPtr.p->m_errorCode);
    ret->setErrorLine(evntRecPtr.p->m_errorLine);
    ret->setErrorNode(evntRecPtr.p->m_errorNode);

    signalLength = CreateEvntRef::SignalLength;
#ifdef EVENT_PH2_DEBUG
    ndbout_c("DBDICT sending GSN_CREATE_EVNT_REF to evntRecPtr.i = (%d) node = %u ref = %u", evntRecPtr.i, refToNode(senderRef), senderRef);
    ndbout_c("errorCode = %u", evntRecPtr.p->m_errorCode);
    ndbout_c("errorLine = %u", evntRecPtr.p->m_errorLine);
#endif
    gsn = GSN_CREATE_EVNT_REF;

  } else {
    jam();
    EVENT_TRACE;
    CreateEvntConf * evntConf = (CreateEvntConf *)signal->getDataPtrSend();
    
    evntConf->setEventId(evntRecPtr.p->m_request.getEventId());
    evntConf->setEventKey(evntRecPtr.p->m_request.getEventKey());
    evntConf->setUserData(evntRecPtr.p->m_request.getUserData());
    evntConf->senderRef = reference();
    evntConf->setTableId(evntRecPtr.p->m_request.getTableId());
    evntConf->setAttrListBitmask(evntRecPtr.p->m_request.getAttrListBitmask());
    evntConf->setEventType(evntRecPtr.p->m_request.getEventType());
    evntConf->setRequestType(evntRecPtr.p->m_request.getRequestType());

    signalLength = CreateEvntConf::SignalLength;
#ifdef EVENT_PH2_DEBUG
    ndbout_c("DBDICT sending GSN_CREATE_EVNT_CONF to evntRecPtr.i = (%d) node = %u ref = %u", evntRecPtr.i, refToNode(senderRef), senderRef);
#endif
    gsn = GSN_CREATE_EVNT_CONF;
  }

  if (ptr) {
    jam();
    sendSignal(senderRef, gsn, signal, signalLength, JBB, ptr, noLSP);
  } else {
    jam();
    sendSignal(senderRef, gsn, signal, signalLength, JBB);
  }

  c_opCreateEvent.release(evntRecPtr);
}

/*************************************************************/

/********************************************************************
 *
 * Start event
 *
 *******************************************************************/

void Dbdict::execSUB_START_REQ(Signal* signal)
{
  jamEntry();

  Uint32 origSenderRef = signal->senderBlockRef();

  OpSubEventPtr subbPtr;
  if (!c_opSubEvent.seize(subbPtr)) {
    SubStartRef * ref = (SubStartRef *)signal->getDataPtrSend();
    { // fix
      Uint32 subcriberRef = ((SubStartReq*)signal->getDataPtr())->subscriberRef;
      ref->subscriberRef = subcriberRef;
    }
    jam();
    //      ret->setErrorCode(SubStartRef::SeizeError);
    //      ret->setErrorLine(__LINE__);
    //      ret->setErrorNode(reference());
    ref->senderRef = reference();
    ref->setTemporary(SubStartRef::Busy);

    sendSignal(origSenderRef, GSN_SUB_START_REF, signal,
	       SubStartRef::SignalLength2, JBB);
    return;
  }

  {
    const SubStartReq* req = (SubStartReq*) signal->getDataPtr();
    subbPtr.p->m_senderRef = req->senderRef;
    subbPtr.p->m_senderData = req->senderData;
    subbPtr.p->m_errorCode = 0;
  }
  
  if (refToBlock(origSenderRef) != DBDICT) {
    /*
     * Coordinator
     */
    jam();
    
    subbPtr.p->m_senderRef = origSenderRef; // not sure if API sets correctly
    NodeReceiverGroup rg(DBDICT, c_aliveNodes);
    RequestTracker & p = subbPtr.p->m_reqTracker;
    p.init<SubStartRef>(c_counterMgr, rg, GSN_SUB_START_REF, subbPtr.i);
    
    SubStartReq* req = (SubStartReq*) signal->getDataPtrSend();
    
    req->senderRef  = reference();
    req->senderData = subbPtr.i;
    
#ifdef EVENT_PH3_DEBUG
    ndbout_c("DBDICT(Coordinator) sending GSN_SUB_START_REQ to DBDICT participants subbPtr.i = (%d)", subbPtr.i);
#endif

    sendSignal(rg, GSN_SUB_START_REQ, signal, SubStartReq::SignalLength2, JBB);
    return;
  }
  /*
   * Participant
   */
  ndbrequire(refToBlock(origSenderRef) == DBDICT);
  
  {
    SubStartReq* req = (SubStartReq*) signal->getDataPtrSend();
    
    req->senderRef = reference();
    req->senderData = subbPtr.i;
    
#ifdef EVENT_PH3_DEBUG
    ndbout_c("DBDICT(Participant) sending GSN_SUB_START_REQ to SUMA subbPtr.i = (%d)", subbPtr.i);
#endif
    sendSignal(SUMA_REF, GSN_SUB_START_REQ, signal, SubStartReq::SignalLength2, JBB);
  }
}

void Dbdict::execSUB_START_REF(Signal* signal)
{
  jamEntry();

  const SubStartRef* ref = (SubStartRef*) signal->getDataPtr();
  Uint32 senderRef  = ref->senderRef;

  OpSubEventPtr subbPtr;
  c_opSubEvent.getPtr(subbPtr, ref->senderData);

  if (refToBlock(senderRef) == SUMA) {
    /*
     * Participant
     */
    jam();

#ifdef EVENT_PH3_DEBUG
    ndbout_c("DBDICT(Participant) got GSN_SUB_START_REF = (%d)", subbPtr.i);
#endif

    if (ref->isTemporary()){
      jam();
      SubStartReq* req = (SubStartReq*)signal->getDataPtrSend();
      { // fix
	Uint32 subscriberRef = ref->subscriberRef;
	req->subscriberRef = subscriberRef;
      }
      req->senderRef  = reference();
      req->senderData = subbPtr.i;
      sendSignal(SUMA_REF, GSN_SUB_START_REQ,
		 signal, SubStartReq::SignalLength2, JBB);
    } else {
      jam();

      SubStartRef* ref = (SubStartRef*) signal->getDataPtrSend();
      ref->senderRef = reference();
      ref->senderData = subbPtr.p->m_senderData;
      sendSignal(subbPtr.p->m_senderRef, GSN_SUB_START_REF,
		 signal, SubStartRef::SignalLength2, JBB);
      c_opSubEvent.release(subbPtr);
    }
    return;
  }
  /*
   * Coordinator
   */
  ndbrequire(refToBlock(senderRef) == DBDICT);
#ifdef EVENT_PH3_DEBUG
  ndbout_c("DBDICT(Coordinator) got GSN_SUB_START_REF = (%d)", subbPtr.i);
#endif
  if (ref->errorCode == SubStartRef::NF_FakeErrorREF){
    jam();
    subbPtr.p->m_reqTracker.ignoreRef(c_counterMgr, refToNode(senderRef));
  } else {
    jam();
    subbPtr.p->m_reqTracker.reportRef(c_counterMgr, refToNode(senderRef));
  }
  completeSubStartReq(signal,subbPtr.i,0);
}

void Dbdict::execSUB_START_CONF(Signal* signal)
{
  jamEntry();

  const SubStartConf* conf = (SubStartConf*) signal->getDataPtr();
  Uint32 senderRef  = conf->senderRef;

  OpSubEventPtr subbPtr;
  c_opSubEvent.getPtr(subbPtr, conf->senderData);

  if (refToBlock(senderRef) == SUMA) {
    /*
     * Participant
     */
    jam();
    SubStartConf* conf = (SubStartConf*) signal->getDataPtrSend();

#ifdef EVENT_PH3_DEBUG
  ndbout_c("DBDICT(Participant) got GSN_SUB_START_CONF = (%d)", subbPtr.i);
#endif

    conf->senderRef = reference();
    conf->senderData = subbPtr.p->m_senderData;

    sendSignal(subbPtr.p->m_senderRef, GSN_SUB_START_CONF,
	       signal, SubStartConf::SignalLength2, JBB);
    c_opSubEvent.release(subbPtr);
    return;
  }
  /*
   * Coordinator
   */
  ndbrequire(refToBlock(senderRef) == DBDICT);
#ifdef EVENT_PH3_DEBUG
  ndbout_c("DBDICT(Coordinator) got GSN_SUB_START_CONF = (%d)", subbPtr.i);
#endif
  subbPtr.p->m_reqTracker.reportConf(c_counterMgr, refToNode(senderRef));
  completeSubStartReq(signal,subbPtr.i,0);
}

/*
 * Coordinator
 */
void Dbdict::completeSubStartReq(Signal* signal,
				 Uint32 ptrI,
				 Uint32 returnCode){
  jam();

  OpSubEventPtr subbPtr;
  c_opSubEvent.getPtr(subbPtr, ptrI);

  if (!subbPtr.p->m_reqTracker.done()){
    jam();
    return;
  }

  if (subbPtr.p->m_reqTracker.hasRef()) {
    jam();
#ifdef EVENT_DEBUG
    ndbout_c("SUB_START_REF");
#endif
    sendSignal(subbPtr.p->m_senderRef, GSN_SUB_START_REF,
	       signal, SubStartRef::SignalLength, JBB);
    if (subbPtr.p->m_reqTracker.hasConf()) {
      //  stopStartedNodes(signal);
    }
    c_opSubEvent.release(subbPtr);
    return;
  }
#ifdef EVENT_DEBUG
  ndbout_c("SUB_START_CONF");
#endif
  sendSignal(subbPtr.p->m_senderRef, GSN_SUB_START_CONF,
	     signal, SubStartConf::SignalLength, JBB);
  c_opSubEvent.release(subbPtr);
}

/********************************************************************
 *
 * Stop event
 *
 *******************************************************************/

void Dbdict::execSUB_STOP_REQ(Signal* signal)
{
  jamEntry();

  Uint32 origSenderRef = signal->senderBlockRef();

  OpSubEventPtr subbPtr;
  if (!c_opSubEvent.seize(subbPtr)) {
    SubStopRef * ref = (SubStopRef *)signal->getDataPtrSend();
    jam();
    //      ret->setErrorCode(SubStartRef::SeizeError);
    //      ret->setErrorLine(__LINE__);
    //      ret->setErrorNode(reference());
    ref->senderRef = reference();
    ref->setTemporary(SubStopRef::Busy);

    sendSignal(origSenderRef, GSN_SUB_STOP_REF, signal,
	       SubStopRef::SignalLength, JBB);
    return;
  }

  {
    const SubStopReq* req = (SubStopReq*) signal->getDataPtr();
    subbPtr.p->m_senderRef = req->senderRef;
    subbPtr.p->m_senderData = req->senderData;
    subbPtr.p->m_errorCode = 0;
  }
  
  if (refToBlock(origSenderRef) != DBDICT) {
    /*
     * Coordinator
     */
    jam();
#ifdef EVENT_DEBUG
    ndbout_c("SUB_STOP_REQ 1");
#endif
    subbPtr.p->m_senderRef = origSenderRef; // not sure if API sets correctly
    NodeReceiverGroup rg(DBDICT, c_aliveNodes);
    RequestTracker & p = subbPtr.p->m_reqTracker;
    p.init<SubStopRef>(c_counterMgr, rg, GSN_SUB_STOP_REF, subbPtr.i);

    SubStopReq* req = (SubStopReq*) signal->getDataPtrSend();

    req->senderRef  = reference();
    req->senderData = subbPtr.i;
    
    sendSignal(rg, GSN_SUB_STOP_REQ, signal, SubStopReq::SignalLength, JBB);
    return;
  }
  /*
   * Participant
   */
#ifdef EVENT_DEBUG
  ndbout_c("SUB_STOP_REQ 2");
#endif
  ndbrequire(refToBlock(origSenderRef) == DBDICT);
  {
    SubStopReq* req = (SubStopReq*) signal->getDataPtrSend();
    
    req->senderRef = reference();
    req->senderData = subbPtr.i;
    
    sendSignal(SUMA_REF, GSN_SUB_STOP_REQ, signal, SubStopReq::SignalLength, JBB);
  }
}

void Dbdict::execSUB_STOP_REF(Signal* signal)
{
  jamEntry();
  const SubStopRef* ref = (SubStopRef*) signal->getDataPtr();
  Uint32 senderRef  = ref->senderRef;

  OpSubEventPtr subbPtr;
  c_opSubEvent.getPtr(subbPtr, ref->senderData);

  if (refToBlock(senderRef) == SUMA) {
    /*
     * Participant
     */
    jam();
    if (ref->isTemporary()){
      jam();
      SubStopReq* req = (SubStopReq*)signal->getDataPtrSend();
      req->senderRef  = reference();
      req->senderData = subbPtr.i;
      sendSignal(SUMA_REF, GSN_SUB_STOP_REQ,
		 signal, SubStopReq::SignalLength, JBB);
    } else {
      jam();
      SubStopRef* ref = (SubStopRef*) signal->getDataPtrSend();
      ref->senderRef = reference();
      ref->senderData = subbPtr.p->m_senderData;
      sendSignal(subbPtr.p->m_senderRef, GSN_SUB_STOP_REF,
		 signal, SubStopRef::SignalLength, JBB);
      c_opSubEvent.release(subbPtr);
    }
    return;
  }
  /*
   * Coordinator
   */
  ndbrequire(refToBlock(senderRef) == DBDICT);
  if (ref->errorCode == SubStopRef::NF_FakeErrorREF){
    jam();
    subbPtr.p->m_reqTracker.ignoreRef(c_counterMgr, refToNode(senderRef));
  } else {
    jam();
    subbPtr.p->m_reqTracker.reportRef(c_counterMgr, refToNode(senderRef));
  }
  completeSubStopReq(signal,subbPtr.i,0);
}

void Dbdict::execSUB_STOP_CONF(Signal* signal)
{
  jamEntry();

  const SubStopConf* conf = (SubStopConf*) signal->getDataPtr();
  Uint32 senderRef  = conf->senderRef;

  OpSubEventPtr subbPtr;
  c_opSubEvent.getPtr(subbPtr, conf->senderData);

  if (refToBlock(senderRef) == SUMA) {
    /*
     * Participant
     */
    jam();
    SubStopConf* conf = (SubStopConf*) signal->getDataPtrSend();

    conf->senderRef = reference();
    conf->senderData = subbPtr.p->m_senderData;

    sendSignal(subbPtr.p->m_senderRef, GSN_SUB_STOP_CONF,
	       signal, SubStopConf::SignalLength, JBB);
    c_opSubEvent.release(subbPtr);
    return;
  }
  /*
   * Coordinator
   */
  ndbrequire(refToBlock(senderRef) == DBDICT);
  subbPtr.p->m_reqTracker.reportConf(c_counterMgr, refToNode(senderRef));
  completeSubStopReq(signal,subbPtr.i,0);
}

/*
 * Coordinator
 */
void Dbdict::completeSubStopReq(Signal* signal,
				Uint32 ptrI,
				Uint32 returnCode){
  OpSubEventPtr subbPtr;
  c_opSubEvent.getPtr(subbPtr, ptrI);

  if (!subbPtr.p->m_reqTracker.done()){
    jam();
    return;
  }

  if (subbPtr.p->m_reqTracker.hasRef()) {
    jam();
#ifdef EVENT_DEBUG
    ndbout_c("SUB_STOP_REF");
#endif
    SubStopRef* ref = (SubStopRef*)signal->getDataPtrSend();

    ref->senderRef      = reference();
    ref->senderData     = subbPtr.p->m_senderData;
    /*
    ref->subscriptionId = subbPtr.p->m_senderData;
    ref->subscriptionKey = subbPtr.p->m_senderData;
    ref->part = subbPtr.p->m_part;  // SubscriptionData::Part
    ref->subscriberData = subbPtr.p->m_subscriberData;
    ref->subscriberRef = subbPtr.p->m_subscriberRef;
    */
    ref->errorCode = subbPtr.p->m_errorCode;


    sendSignal(subbPtr.p->m_senderRef, GSN_SUB_STOP_REF,
	       signal, SubStopRef::SignalLength, JBB);
    if (subbPtr.p->m_reqTracker.hasConf()) {
      //  stopStartedNodes(signal);
    }
    c_opSubEvent.release(subbPtr);
    return;
  }
#ifdef EVENT_DEBUG
  ndbout_c("SUB_STOP_CONF");
#endif
  sendSignal(subbPtr.p->m_senderRef, GSN_SUB_STOP_CONF,
	     signal, SubStopConf::SignalLength, JBB);
  c_opSubEvent.release(subbPtr);
}

/***************************************************************
 * MODULE: Drop event.
 *
 * Drop event.
 * 
 * TODO
 */

void
Dbdict::execDROP_EVNT_REQ(Signal* signal)
{
  jamEntry();
  EVENT_TRACE;

  DropEvntReq *req = (DropEvntReq*)signal->getDataPtr();
  const Uint32 senderRef = signal->senderBlockRef();
  OpDropEventPtr evntRecPtr;

  // Seize a Create Event record
  if (!c_opDropEvent.seize(evntRecPtr)) {
    // Failed to allocate event record
    jam();
    releaseSections(signal);
 
    DropEvntRef * ret = (DropEvntRef *)signal->getDataPtrSend();
    ret->setErrorCode(DropEvntRef::SeizeError);
    ret->setErrorLine(__LINE__);
    ret->setErrorNode(reference());
    sendSignal(senderRef, GSN_DROP_EVNT_REF, signal,
	       DropEvntRef::SignalLength, JBB);
    return;
  }

#ifdef EVENT_DEBUG
  ndbout_c("DBDICT::execDROP_EVNT_REQ evntRecId = (%d)", evntRecPtr.i);
#endif

  OpDropEvent* evntRec = evntRecPtr.p;
  evntRec->init(req);

  SegmentedSectionPtr ssPtr;

  signal->getSection(ssPtr, 0);

  SimplePropertiesSectionReader r0(ssPtr, getSectionSegmentPool());
#ifdef EVENT_DEBUG
  r0.printAll(ndbout);
#endif
  // event name
  if ((!r0.first()) ||
      (r0.getValueType() != SimpleProperties::StringValue) ||
      (r0.getValueLen() <= 0)) {
    jam();
    releaseSections(signal);

    evntRecPtr.p->m_errorCode = DropEvntRef::Undefined;
    evntRecPtr.p->m_errorLine = __LINE__;
    evntRecPtr.p->m_errorNode = reference();

    dropEvent_sendReply(signal, evntRecPtr);
    return;
  }
  r0.getString(evntRecPtr.p->m_eventRec.NAME);
  {
    int len = strlen(evntRecPtr.p->m_eventRec.NAME);
    memset(evntRecPtr.p->m_eventRec.NAME+len, 0, MAX_TAB_NAME_SIZE-len);
#ifdef EVENT_DEBUG
    printf("DropEvntReq; EventName %s, len %u\n",
	   evntRecPtr.p->m_eventRec.NAME, len);
    for(int i = 0; i < MAX_TAB_NAME_SIZE/4; i++)
      printf("H'%.8x ", ((Uint32*)evntRecPtr.p->m_eventRec.NAME)[i]);
    printf("\n");
#endif
  }
  
  releaseSections(signal);

  Callback c = { safe_cast(&Dbdict::dropEventUTIL_PREPARE_READ), 0 };

  prepareTransactionEventSysTable(&c, signal, evntRecPtr.i,
				  UtilPrepareReq::Read);
}

void 
Dbdict::dropEventUTIL_PREPARE_READ(Signal* signal,
				   Uint32 callbackData,
				   Uint32 returnCode)
{
  jam();
  EVENT_TRACE;
  if (returnCode != 0) {
    EVENT_TRACE;
    dropEventUtilPrepareRef(signal, callbackData, returnCode);
    return;
  }

  UtilPrepareConf* const req = (UtilPrepareConf*)signal->getDataPtr();
  OpDropEventPtr evntRecPtr;
  evntRecPtr.i = req->getSenderData();
  const Uint32 prepareId = req->getPrepareId();

  ndbrequire((evntRecPtr.p = c_opDropEvent.getPtr(evntRecPtr.i)) != NULL);

  Callback c = { safe_cast(&Dbdict::dropEventUTIL_EXECUTE_READ), 0 };

  executeTransEventSysTable(&c, signal,
			    evntRecPtr.i, evntRecPtr.p->m_eventRec,
			    prepareId, UtilPrepareReq::Read);
}

void 
Dbdict::dropEventUTIL_EXECUTE_READ(Signal* signal,
				   Uint32 callbackData,
				   Uint32 returnCode)
{
  jam();
  EVENT_TRACE;
  if (returnCode != 0) {
    EVENT_TRACE;
    dropEventUtilExecuteRef(signal, callbackData, returnCode);
    return;
  }

  OpDropEventPtr evntRecPtr;
  UtilExecuteConf * const ref = (UtilExecuteConf *)signal->getDataPtr();
  jam();
  evntRecPtr.i = ref->getSenderData();
  ndbrequire((evntRecPtr.p = c_opDropEvent.getPtr(evntRecPtr.i)) != NULL);

  parseReadEventSys(signal, evntRecPtr.p->m_eventRec);

  NodeReceiverGroup rg(DBDICT, c_aliveNodes);
  RequestTracker & p = evntRecPtr.p->m_reqTracker;
  p.init<SubRemoveRef>(c_counterMgr, rg, GSN_SUB_REMOVE_REF,
						evntRecPtr.i);

  SubRemoveReq* req = (SubRemoveReq*) signal->getDataPtrSend();

  req->senderRef       = reference();
  req->senderData      = evntRecPtr.i;
  req->subscriptionId  = evntRecPtr.p->m_eventRec.SUBID;
  req->subscriptionKey = evntRecPtr.p->m_eventRec.SUBKEY;

  sendSignal(rg, GSN_SUB_REMOVE_REQ, signal, SubRemoveReq::SignalLength, JBB);
}

/*
 * Participant
 */

void
Dbdict::execSUB_REMOVE_REQ(Signal* signal)
{
  jamEntry();

  Uint32 origSenderRef = signal->senderBlockRef();

  OpSubEventPtr subbPtr;
  if (!c_opSubEvent.seize(subbPtr)) {
    SubRemoveRef * ref = (SubRemoveRef *)signal->getDataPtrSend();
    jam();
    ref->senderRef = reference();
    ref->setTemporary(SubRemoveRef::Busy);

    sendSignal(origSenderRef, GSN_SUB_REMOVE_REF, signal,
	       SubRemoveRef::SignalLength, JBB);
    return;
  }

  {
    const SubRemoveReq* req = (SubRemoveReq*) signal->getDataPtr();
    subbPtr.p->m_senderRef = req->senderRef;
    subbPtr.p->m_senderData = req->senderData;
    subbPtr.p->m_errorCode = 0;
  }

  SubRemoveReq* req = (SubRemoveReq*) signal->getDataPtrSend();
  req->senderRef = reference();
  req->senderData = subbPtr.i;

  sendSignal(SUMA_REF, GSN_SUB_REMOVE_REQ, signal, SubRemoveReq::SignalLength, JBB);
}

/*
 * Coordintor/Participant
 */

void
Dbdict::execSUB_REMOVE_REF(Signal* signal)
{
  jamEntry();
  const SubRemoveRef* ref = (SubRemoveRef*) signal->getDataPtr();
  Uint32 senderRef = ref->senderRef;

  if (refToBlock(senderRef) == SUMA) {
    /*
     * Participant
     */
    jam();
    OpSubEventPtr subbPtr;
    c_opSubEvent.getPtr(subbPtr, ref->senderData);
    if (ref->errorCode == (Uint32) GrepError::SUBSCRIPTION_ID_NOT_FOUND) {
      // conf this since this may occur if a nodefailiure has occured
      // earlier so that the systable was not cleared
      SubRemoveConf* conf = (SubRemoveConf*) signal->getDataPtrSend();
      conf->senderRef  = reference();
      conf->senderData = subbPtr.p->m_senderData;
      sendSignal(subbPtr.p->m_senderRef, GSN_SUB_REMOVE_CONF,
		 signal, SubRemoveConf::SignalLength, JBB);
    } else {
      SubRemoveRef* ref = (SubRemoveRef*) signal->getDataPtrSend();
      ref->senderRef = reference();
      ref->senderData = subbPtr.p->m_senderData;
      sendSignal(subbPtr.p->m_senderRef, GSN_SUB_REMOVE_REF,
		 signal, SubRemoveRef::SignalLength, JBB);
    }
    c_opSubEvent.release(subbPtr);
    return;
  }
  /*
   * Coordinator
   */
  ndbrequire(refToBlock(senderRef) == DBDICT);
  OpDropEventPtr eventRecPtr;
  c_opDropEvent.getPtr(eventRecPtr, ref->senderData);
  if (ref->errorCode == SubRemoveRef::NF_FakeErrorREF){
    jam();
    eventRecPtr.p->m_reqTracker.ignoreRef(c_counterMgr, refToNode(senderRef));
  } else {
    jam();
    eventRecPtr.p->m_reqTracker.reportRef(c_counterMgr, refToNode(senderRef));
  }
  completeSubRemoveReq(signal,eventRecPtr.i,0);
}

void
Dbdict::execSUB_REMOVE_CONF(Signal* signal)
{
  jamEntry();
  const SubRemoveConf* conf = (SubRemoveConf*) signal->getDataPtr();
  Uint32 senderRef = conf->senderRef;

  if (refToBlock(senderRef) == SUMA) {
    /*
     * Participant
     */
    jam();
    OpSubEventPtr subbPtr;
    c_opSubEvent.getPtr(subbPtr, conf->senderData);
    SubRemoveConf* conf = (SubRemoveConf*) signal->getDataPtrSend();
    conf->senderRef = reference();
    conf->senderData = subbPtr.p->m_senderData;
    sendSignal(subbPtr.p->m_senderRef, GSN_SUB_REMOVE_CONF,
	       signal, SubRemoveConf::SignalLength, JBB);
    c_opSubEvent.release(subbPtr);
    return;
  }
  /*
   * Coordinator
   */
  ndbrequire(refToBlock(senderRef) == DBDICT);
  OpDropEventPtr eventRecPtr;
  c_opDropEvent.getPtr(eventRecPtr, conf->senderData);
  eventRecPtr.p->m_reqTracker.reportConf(c_counterMgr, refToNode(senderRef));
  completeSubRemoveReq(signal,eventRecPtr.i,0);
}

void
Dbdict::completeSubRemoveReq(Signal* signal, Uint32 ptrI, Uint32 xxx)
{
  OpDropEventPtr evntRecPtr;
  c_opDropEvent.getPtr(evntRecPtr, ptrI);

  if (!evntRecPtr.p->m_reqTracker.done()){
    jam();
    return;
  }

  if (evntRecPtr.p->m_reqTracker.hasRef()) {
    jam();
    evntRecPtr.p->m_errorNode = reference();
    evntRecPtr.p->m_errorLine = __LINE__;
    evntRecPtr.p->m_errorCode = DropEvntRef::Undefined;
    dropEvent_sendReply(signal, evntRecPtr);
    return;
  }

  Callback c = { safe_cast(&Dbdict::dropEventUTIL_PREPARE_DELETE), 0 };

  prepareTransactionEventSysTable(&c, signal, evntRecPtr.i,
				  UtilPrepareReq::Delete);
}

void 
Dbdict::dropEventUTIL_PREPARE_DELETE(Signal* signal,
				     Uint32 callbackData,
				     Uint32 returnCode)
{
  jam();
  EVENT_TRACE;
  if (returnCode != 0) {
    EVENT_TRACE;
    dropEventUtilPrepareRef(signal, callbackData, returnCode);
    return;
  }

  UtilPrepareConf* const req = (UtilPrepareConf*)signal->getDataPtr();
  OpDropEventPtr evntRecPtr;
  jam();
  evntRecPtr.i = req->getSenderData();
  const Uint32 prepareId = req->getPrepareId();
  
  ndbrequire((evntRecPtr.p = c_opDropEvent.getPtr(evntRecPtr.i)) != NULL);
#ifdef EVENT_DEBUG
  printf("DropEvntUTIL_PREPARE; evntRecPtr.i len %u\n",evntRecPtr.i);
#endif    

  Callback c = { safe_cast(&Dbdict::dropEventUTIL_EXECUTE_DELETE), 0 };

  executeTransEventSysTable(&c, signal,
			    evntRecPtr.i, evntRecPtr.p->m_eventRec,
			    prepareId, UtilPrepareReq::Delete);
}

void 
Dbdict::dropEventUTIL_EXECUTE_DELETE(Signal* signal,
				     Uint32 callbackData,
				     Uint32 returnCode)
{
  jam();
  EVENT_TRACE;
  if (returnCode != 0) {
    EVENT_TRACE;
    dropEventUtilExecuteRef(signal, callbackData, returnCode);
    return;
  }

  OpDropEventPtr evntRecPtr;
  UtilExecuteConf * const ref = (UtilExecuteConf *)signal->getDataPtr();
  jam();
  evntRecPtr.i = ref->getSenderData();
  ndbrequire((evntRecPtr.p = c_opDropEvent.getPtr(evntRecPtr.i)) != NULL);

  dropEvent_sendReply(signal, evntRecPtr);
}

void
Dbdict::dropEventUtilPrepareRef(Signal* signal,
				Uint32 callbackData,
				Uint32 returnCode)
{
  jam();
  EVENT_TRACE;
  UtilPrepareRef * const ref = (UtilPrepareRef *)signal->getDataPtr();
  OpDropEventPtr evntRecPtr;
  evntRecPtr.i = ref->getSenderData();
  ndbrequire((evntRecPtr.p = c_opDropEvent.getPtr(evntRecPtr.i)) != NULL);

  bool temporary = false;
  interpretUtilPrepareErrorCode((UtilPrepareRef::ErrorCode)ref->getErrorCode(),
				temporary, evntRecPtr.p->m_errorLine);
  if (temporary) {
    evntRecPtr.p->m_errorCode = (DropEvntRef::ErrorCode)
      ((Uint32) DropEvntRef::Undefined | (Uint32) DropEvntRef::Temporary);
  }

  if (evntRecPtr.p->m_errorCode == 0) {
    evntRecPtr.p->m_errorCode = DropEvntRef::Undefined;
    evntRecPtr.p->m_errorLine = __LINE__;
  }
  evntRecPtr.p->m_errorNode = reference();

  dropEvent_sendReply(signal, evntRecPtr);
}

void
Dbdict::dropEventUtilExecuteRef(Signal* signal,
				Uint32 callbackData,
				Uint32 returnCode)
{
  jam();
  EVENT_TRACE;
  OpDropEventPtr evntRecPtr;
  UtilExecuteRef * const ref = (UtilExecuteRef *)signal->getDataPtr();
  jam();
  evntRecPtr.i = ref->getSenderData();
  ndbrequire((evntRecPtr.p = c_opDropEvent.getPtr(evntRecPtr.i)) != NULL);
    
  evntRecPtr.p->m_errorNode = reference();
  evntRecPtr.p->m_errorLine = __LINE__;

  switch (ref->getErrorCode()) {
  case UtilExecuteRef::TCError:
    switch (ref->getTCErrorCode()) {
    case ZNOT_FOUND:
      jam();
      evntRecPtr.p->m_errorCode = DropEvntRef::EventNotFound;
      break;
    default:
      jam();
      evntRecPtr.p->m_errorCode = DropEvntRef::UndefinedTCError;
      break;
    }
    break;
  default:
    jam();
    evntRecPtr.p->m_errorCode = DropEvntRef::Undefined;
    break;
  }
  dropEvent_sendReply(signal, evntRecPtr);
}

void Dbdict::dropEvent_sendReply(Signal* signal,
				 OpDropEventPtr evntRecPtr)
{
  jam();
  EVENT_TRACE;
  Uint32 senderRef = evntRecPtr.p->m_request.getUserRef();

  if (evntRecPtr.p->hasError()) {
    jam();
    DropEvntRef * ret = (DropEvntRef *)signal->getDataPtrSend();
    
    ret->setUserData(evntRecPtr.p->m_request.getUserData());
    ret->setUserRef(evntRecPtr.p->m_request.getUserRef());

    ret->setErrorCode(evntRecPtr.p->m_errorCode);
    ret->setErrorLine(evntRecPtr.p->m_errorLine);
    ret->setErrorNode(evntRecPtr.p->m_errorNode);

    sendSignal(senderRef, GSN_DROP_EVNT_REF, signal,
	       DropEvntRef::SignalLength, JBB);
  } else {
    jam();
    DropEvntConf * evntConf = (DropEvntConf *)signal->getDataPtrSend();
    
    evntConf->setUserData(evntRecPtr.p->m_request.getUserData());
    evntConf->setUserRef(evntRecPtr.p->m_request.getUserRef());

    sendSignal(senderRef, GSN_DROP_EVNT_CONF, signal,
	       DropEvntConf::SignalLength, JBB);
  }

  c_opDropEvent.release(evntRecPtr);
}

/**
 * MODULE: Alter index
 *
 * Alter index state.  Alter online creates the index in each TC and
 * then invokes create trigger and alter trigger protocols to activate
 * the 3 triggers.  Alter offline does the opposite.
 *
 * Request type received in REQ and returned in CONF/REF:
 *
 * RT_USER - from API to DICT master
 * RT_CREATE_INDEX - part of create index operation
 * RT_DROP_INDEX - part of drop index operation
 * RT_NODERESTART - node restart, activate locally only
 * RT_SYSTEMRESTART - system restart, activate and build if not logged
 * RT_DICT_PREPARE - prepare participants
 * RT_DICT_TC - to local TC via each participant
 * RT_DICT_COMMIT - commit in each participant
 */

void
Dbdict::execALTER_INDX_REQ(Signal* signal)
{
  jamEntry();
  AlterIndxReq* const req = (AlterIndxReq*)signal->getDataPtrSend();
  OpAlterIndexPtr opPtr;
  const Uint32 senderRef = signal->senderBlockRef();
  const AlterIndxReq::RequestType requestType = req->getRequestType();
  if (requestType == AlterIndxReq::RT_USER ||
      requestType == AlterIndxReq::RT_CREATE_INDEX ||
      requestType == AlterIndxReq::RT_DROP_INDEX ||
      requestType == AlterIndxReq::RT_NODERESTART ||
      requestType == AlterIndxReq::RT_SYSTEMRESTART) {
    jam();
    const bool isLocal = req->getRequestFlag() & RequestFlag::RF_LOCAL;
    NdbNodeBitmask receiverNodes = c_aliveNodes;
    if (isLocal) {
      receiverNodes.clear();
      receiverNodes.set(getOwnNodeId());
    }
    if (signal->getLength() == AlterIndxReq::SignalLength) {
      jam();
      if (! isLocal && getOwnNodeId() != c_masterNodeId) {
        jam();
        // forward to DICT master
        sendSignal(calcDictBlockRef(c_masterNodeId), GSN_ALTER_INDX_REQ,
            signal, signal->getLength(), JBB);
        return;
      }
      // forward initial request plus operation key to all
      req->setOpKey(++c_opRecordSequence);
      NodeReceiverGroup rg(DBDICT, receiverNodes);
      sendSignal(rg, GSN_ALTER_INDX_REQ,
          signal, AlterIndxReq::SignalLength + 1, JBB);
      return;
    }
    // seize operation record
    ndbrequire(signal->getLength() == AlterIndxReq::SignalLength + 1);
    const Uint32 opKey = req->getOpKey();
    OpAlterIndex opBusy;
    if (! c_opAlterIndex.seize(opPtr))
      opPtr.p = &opBusy;
    opPtr.p->save(req);
    opPtr.p->m_coordinatorRef = senderRef;
    opPtr.p->m_isMaster = (senderRef == reference());
    opPtr.p->key = opKey;
    opPtr.p->m_requestType = AlterIndxReq::RT_DICT_PREPARE;
    if (opPtr.p == &opBusy) {
      jam();
      opPtr.p->m_errorCode = AlterIndxRef::Busy;
      opPtr.p->m_errorLine = __LINE__;
      alterIndex_sendReply(signal, opPtr, opPtr.p->m_isMaster);
      return;
    }
    c_opAlterIndex.add(opPtr);
    // master expects to hear from all
    if (opPtr.p->m_isMaster)
      opPtr.p->m_signalCounter = receiverNodes;
    // check request in all participants
    alterIndex_slavePrepare(signal, opPtr);
    alterIndex_sendReply(signal, opPtr, false);
    return;
  }
  c_opAlterIndex.find(opPtr, req->getConnectionPtr());
  if (! opPtr.isNull()) {
    opPtr.p->m_requestType = requestType;
    if (requestType == AlterIndxReq::RT_DICT_TC) {
      jam();
      if (opPtr.p->m_request.getOnline())
        alterIndex_toCreateTc(signal, opPtr);
      else
        alterIndex_toDropTc(signal, opPtr);
      return;
    }
    if (requestType == AlterIndxReq::RT_DICT_COMMIT ||
        requestType == AlterIndxReq::RT_DICT_ABORT) {
      jam();
      if (requestType == AlterIndxReq::RT_DICT_COMMIT)
        alterIndex_slaveCommit(signal, opPtr);
      else
        alterIndex_slaveAbort(signal, opPtr);
      alterIndex_sendReply(signal, opPtr, false);
      // done in slave
      if (! opPtr.p->m_isMaster)
        c_opAlterIndex.release(opPtr);
      return;
    }
  }
  jam();
  // return to sender
  OpAlterIndex opBad;
  opPtr.p = &opBad;
  opPtr.p->save(req);
  opPtr.p->m_errorCode = AlterIndxRef::BadRequestType;
  opPtr.p->m_errorLine = __LINE__;
  alterIndex_sendReply(signal, opPtr, true);
}

void
Dbdict::execALTER_INDX_CONF(Signal* signal)
{
  jamEntry();
  ndbrequire(signal->getNoOfSections() == 0);
  AlterIndxConf* conf = (AlterIndxConf*)signal->getDataPtrSend();
  alterIndex_recvReply(signal, conf, 0);
}

void
Dbdict::execALTER_INDX_REF(Signal* signal)
{
  jamEntry();
  AlterIndxRef* ref = (AlterIndxRef*)signal->getDataPtrSend();
  alterIndex_recvReply(signal, ref->getConf(), ref);
}

void
Dbdict::alterIndex_recvReply(Signal* signal, const AlterIndxConf* conf,
    const AlterIndxRef* ref)
{
  jam();
  const Uint32 senderRef = signal->senderBlockRef();
  const AlterIndxReq::RequestType requestType = conf->getRequestType();
  const Uint32 key = conf->getConnectionPtr();
  if (requestType == AlterIndxReq::RT_CREATE_INDEX) {
    jam();
    // part of create index operation
    OpCreateIndexPtr opPtr;
    c_opCreateIndex.find(opPtr, key);
    ndbrequire(! opPtr.isNull());
    opPtr.p->setError(ref);
    createIndex_fromAlterIndex(signal, opPtr);
    return;
  }
  if (requestType == AlterIndxReq::RT_DROP_INDEX) {
    jam();
    // part of drop index operation
    OpDropIndexPtr opPtr;
    c_opDropIndex.find(opPtr, key);
    ndbrequire(! opPtr.isNull());
    opPtr.p->setError(ref);
    dropIndex_fromAlterIndex(signal, opPtr);
    return;
  }
  if (requestType == AlterIndxReq::RT_TC ||
      requestType == AlterIndxReq::RT_TUX) {
    jam();
    // part of build index operation
    OpBuildIndexPtr opPtr;
    c_opBuildIndex.find(opPtr, key);
    ndbrequire(! opPtr.isNull());
    opPtr.p->setError(ref);
    buildIndex_fromOnline(signal, opPtr);
    return;
  }
  if (requestType == AlterIndxReq::RT_NODERESTART) {
    jam();
    if (ref == 0) {
      infoEvent("DICT: index %u activated", (unsigned)key);
    } else {
      warningEvent("DICT: index %u activation failed: code=%d line=%d",
          (unsigned)key,
          ref->getErrorCode(), ref->getErrorLine());
    }
    activateIndexes(signal, key + 1);
    return;
  }
  if (requestType == AlterIndxReq::RT_SYSTEMRESTART) {
    jam();
    if (ref == 0) {
      infoEvent("DICT: index %u activated done", (unsigned)key);
    } else {
      warningEvent("DICT: index %u activated failed: code=%d line=%d node=%d",
          (unsigned)key,
          ref->getErrorCode(), ref->getErrorLine(), ref->getErrorNode());
    }
    activateIndexes(signal, key + 1);
    return;
  }
  OpAlterIndexPtr opPtr;
  c_opAlterIndex.find(opPtr, key);
  ndbrequire(! opPtr.isNull());
  ndbrequire(opPtr.p->m_isMaster);
  ndbrequire(opPtr.p->m_requestType == requestType);
  opPtr.p->setError(ref);
  opPtr.p->m_signalCounter.clearWaitingFor(refToNode(senderRef));
  if (! opPtr.p->m_signalCounter.done()) {
    jam();
    return;
  }
  if (requestType == AlterIndxReq::RT_DICT_COMMIT ||
      requestType == AlterIndxReq::RT_DICT_ABORT) {
    jam();
    // send reply to user
    alterIndex_sendReply(signal, opPtr, true);
    c_opAlterIndex.release(opPtr);
    return;
  }
  if (opPtr.p->hasError()) {
    jam();
    opPtr.p->m_requestType = AlterIndxReq::RT_DICT_ABORT;
    alterIndex_sendSlaveReq(signal, opPtr);
    return;
  }
  TableRecordPtr indexPtr;
  c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId());
  if (indexPtr.p->isHashIndex()) {
    if (requestType == AlterIndxReq::RT_DICT_PREPARE) {
      jam();
      if (opPtr.p->m_request.getOnline()) {
        opPtr.p->m_requestType = AlterIndxReq::RT_DICT_TC;
        alterIndex_sendSlaveReq(signal, opPtr);
      } else {
        // start drop triggers
        alterIndex_toDropTrigger(signal, opPtr);
      }
      return;
    }
    if (requestType == AlterIndxReq::RT_DICT_TC) {
      jam();
      if (opPtr.p->m_request.getOnline()) {
        // start create triggers
        alterIndex_toCreateTrigger(signal, opPtr);
      } else {
        opPtr.p->m_requestType = AlterIndxReq::RT_DICT_COMMIT;
        alterIndex_sendSlaveReq(signal, opPtr);
      }
      return;
    }
  }
  if (indexPtr.p->isOrderedIndex()) {
    if (requestType == AlterIndxReq::RT_DICT_PREPARE) {
      jam();
      if (opPtr.p->m_request.getOnline()) {
        // start create triggers
        alterIndex_toCreateTrigger(signal, opPtr);
      } else {
        // start drop triggers
        alterIndex_toDropTrigger(signal, opPtr);
      }
      return;
    }
  }
  ndbrequire(false);
}

void
Dbdict::alterIndex_slavePrepare(Signal* signal, OpAlterIndexPtr opPtr)
{
  jam();
  const AlterIndxReq* const req = &opPtr.p->m_request;
  if (! (req->getIndexId() < c_tableRecordPool.getSize())) {
    jam();
    opPtr.p->m_errorCode = AlterIndxRef::Inconsistency;
    opPtr.p->m_errorLine = __LINE__;
    return;
  }
  TableRecordPtr indexPtr;
  c_tableRecordPool.getPtr(indexPtr, req->getIndexId());
  if (indexPtr.p->tabState != TableRecord::DEFINED) {
    jam();
    opPtr.p->m_errorCode = AlterIndxRef::IndexNotFound;
    opPtr.p->m_errorLine = __LINE__;
    return;
  }
  if (! indexPtr.p->isIndex()) {
    jam();
    opPtr.p->m_errorCode = AlterIndxRef::NotAnIndex;
    opPtr.p->m_errorLine = __LINE__;
    return;
  }
  if (req->getOnline())
    indexPtr.p->indexState = TableRecord::IS_BUILDING;
  else
    indexPtr.p->indexState = TableRecord::IS_DROPPING;
}

void
Dbdict::alterIndex_toCreateTc(Signal* signal, OpAlterIndexPtr opPtr)
{
  jam();
  TableRecordPtr indexPtr;
  c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId());
  // request to create index in local TC
  CreateIndxReq* const req = (CreateIndxReq*)signal->getDataPtrSend();
  req->setUserRef(reference());
  req->setConnectionPtr(opPtr.p->key);
  req->setRequestType(CreateIndxReq::RT_TC);
  req->setIndexType(indexPtr.p->tableType);
  req->setTableId(indexPtr.p->primaryTableId);
  req->setIndexId(indexPtr.i);
  req->setOnline(true);
  getIndexAttrList(indexPtr, opPtr.p->m_attrList);
  // send
  LinearSectionPtr lsPtr[3];
  lsPtr[0].p = (Uint32*)&opPtr.p->m_attrList;
  lsPtr[0].sz = 1 + opPtr.p->m_attrList.sz;
  sendSignal(calcTcBlockRef(getOwnNodeId()), GSN_CREATE_INDX_REQ,
      signal, CreateIndxReq::SignalLength, JBB, lsPtr, 1);
}

void
Dbdict::alterIndex_fromCreateTc(Signal* signal, OpAlterIndexPtr opPtr)
{
  jam();
  // mark created in local TC
  if (! opPtr.p->hasError()) {
    TableRecordPtr indexPtr;
    c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId());
    indexPtr.p->indexLocal |= TableRecord::IL_CREATED_TC;
  }
  // forward CONF or REF to master
  ndbrequire(opPtr.p->m_requestType == AlterIndxReq::RT_DICT_TC);
  alterIndex_sendReply(signal, opPtr, false);
}

void
Dbdict::alterIndex_toDropTc(Signal* signal, OpAlterIndexPtr opPtr)
{
  jam();
  TableRecordPtr indexPtr;
  c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId());
  // broken index
  if (! (indexPtr.p->indexLocal & TableRecord::IL_CREATED_TC)) {
    jam();
    alterIndex_sendReply(signal, opPtr, false);
    return;
  }
  // request to drop in local TC
  DropIndxReq* const req = (DropIndxReq*)signal->getDataPtrSend();
  req->setUserRef(reference());
  req->setConnectionPtr(opPtr.p->key);
  req->setRequestType(DropIndxReq::RT_TC);
  req->setTableId(indexPtr.p->primaryTableId);
  req->setIndexId(indexPtr.i);
  req->setIndexVersion(indexPtr.p->tableVersion);
  // send
  sendSignal(calcTcBlockRef(getOwnNodeId()), GSN_DROP_INDX_REQ,
      signal, DropIndxReq::SignalLength, JBB);
}

void
Dbdict::alterIndex_fromDropTc(Signal* signal, OpAlterIndexPtr opPtr)
{
  jam();
  ndbrequire(opPtr.p->m_requestType == AlterIndxReq::RT_DICT_TC);
  if (! opPtr.p->hasError()) {
    // mark dropped in local TC
    TableRecordPtr indexPtr;
    c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId());
    indexPtr.p->indexLocal &= ~TableRecord::IL_CREATED_TC;
  }
  // forward CONF or REF to master
  alterIndex_sendReply(signal, opPtr, false);
}

void
Dbdict::alterIndex_toCreateTrigger(Signal* signal, OpAlterIndexPtr opPtr)
{
  jam();
  TableRecordPtr indexPtr;
  c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId());
  // start creation of index triggers
  CreateTrigReq* const req = (CreateTrigReq*)signal->getDataPtrSend();
  req->setUserRef(reference());
  req->setConnectionPtr(opPtr.p->key);
  req->setRequestType(CreateTrigReq::RT_ALTER_INDEX);
  req->addRequestFlag(opPtr.p->m_requestFlag);
  req->setTableId(opPtr.p->m_request.getTableId());
  req->setIndexId(opPtr.p->m_request.getIndexId());
  req->setTriggerId(RNIL);
  req->setTriggerActionTime(TriggerActionTime::TA_AFTER);
  req->setMonitorAllAttributes(false);
  req->setOnline(true);         // alter online after create
  req->setReceiverRef(0);       // implicit for index triggers
  getIndexAttrMask(indexPtr, req->getAttributeMask());
  // name section
  char triggerName[MAX_TAB_NAME_SIZE];
  Uint32 buffer[2 + ((MAX_TAB_NAME_SIZE + 3) >> 2)];    // SP string
  LinearWriter w(buffer, sizeof(buffer) >> 2);
  LinearSectionPtr lsPtr[3];
  if (indexPtr.p->isHashIndex()) {
    req->setTriggerType(TriggerType::SECONDARY_INDEX);
    req->setMonitorReplicas(false);
    // insert
    if (opPtr.p->m_requestFlag & RequestFlag::RF_LOCAL)
      req->setTriggerId(indexPtr.p->insertTriggerId);
    req->setTriggerEvent(TriggerEvent::TE_INSERT);
    sprintf(triggerName, "NDB$INDEX_%u_INSERT", opPtr.p->m_request.getIndexId());
    w.reset();
    w.add(CreateTrigReq::TriggerNameKey, triggerName);
    lsPtr[0].p = buffer;
    lsPtr[0].sz = w.getWordsUsed();
    sendSignal(reference(), GSN_CREATE_TRIG_REQ, 
        signal, CreateTrigReq::SignalLength, JBB, lsPtr, 1);
    // update
    if (opPtr.p->m_requestFlag & RequestFlag::RF_LOCAL)
      req->setTriggerId(indexPtr.p->updateTriggerId);
    req->setTriggerEvent(TriggerEvent::TE_UPDATE);
    sprintf(triggerName, "NDB$INDEX_%u_UPDATE", opPtr.p->m_request.getIndexId());
    w.reset();
    w.add(CreateTrigReq::TriggerNameKey, triggerName);
    lsPtr[0].p = buffer;
    lsPtr[0].sz = w.getWordsUsed();
    sendSignal(reference(), GSN_CREATE_TRIG_REQ, 
        signal, CreateTrigReq::SignalLength, JBB, lsPtr, 1);
    // delete
    if (opPtr.p->m_requestFlag & RequestFlag::RF_LOCAL)
      req->setTriggerId(indexPtr.p->deleteTriggerId);
    req->setTriggerEvent(TriggerEvent::TE_DELETE);
    sprintf(triggerName, "NDB$INDEX_%u_DELETE", opPtr.p->m_request.getIndexId());
    w.reset();
    w.add(CreateTrigReq::TriggerNameKey, triggerName);
    lsPtr[0].p = buffer;
    lsPtr[0].sz = w.getWordsUsed();
    sendSignal(reference(), GSN_CREATE_TRIG_REQ, 
        signal, CreateTrigReq::SignalLength, JBB, lsPtr, 1);
    // triggers left to create
    opPtr.p->m_triggerCounter = 3;
    return;
  }
  if (indexPtr.p->isOrderedIndex()) {
    req->addRequestFlag(RequestFlag::RF_NOTCTRIGGER);
    req->setTriggerType(TriggerType::ORDERED_INDEX);
    req->setTriggerActionTime(TriggerActionTime::TA_CUSTOM);
    req->setMonitorReplicas(true);
    // one trigger for 5 events (insert, update, delete, commit, abort)
    if (opPtr.p->m_requestFlag & RequestFlag::RF_LOCAL)
      req->setTriggerId(indexPtr.p->customTriggerId);
    req->setTriggerEvent(TriggerEvent::TE_CUSTOM);
    sprintf(triggerName, "NDB$INDEX_%u_CUSTOM", opPtr.p->m_request.getIndexId());
    w.reset();
    w.add(CreateTrigReq::TriggerNameKey, triggerName);
    lsPtr[0].p = buffer;
    lsPtr[0].sz = w.getWordsUsed();
    sendSignal(reference(), GSN_CREATE_TRIG_REQ, 
        signal, CreateTrigReq::SignalLength, JBB, lsPtr, 1);
    // triggers left to create
    opPtr.p->m_triggerCounter = 1;
    return;
  }
  ndbrequire(false);
}

void
Dbdict::alterIndex_fromCreateTrigger(Signal* signal, OpAlterIndexPtr opPtr)
{
  jam();
  ndbrequire(opPtr.p->m_triggerCounter != 0);
  if (--opPtr.p->m_triggerCounter != 0) {
    jam();
    return;
  }
  if (opPtr.p->hasError()) {
    jam();
    opPtr.p->m_requestType = AlterIndxReq::RT_DICT_ABORT;
    alterIndex_sendSlaveReq(signal, opPtr);
    return;
  }
  if(opPtr.p->m_requestType != AlterIndxReq::RT_SYSTEMRESTART){
    // send build request
    alterIndex_toBuildIndex(signal, opPtr);
    return;
  }
  
  /**
   * During system restart, 
   *   leave index in activated but not build state.
   *
   * Build a bit later when REDO has been run
   */
  alterIndex_sendReply(signal, opPtr, true);
}

void
Dbdict::alterIndex_toDropTrigger(Signal* signal, OpAlterIndexPtr opPtr)
{
  jam();
  TableRecordPtr indexPtr;
  c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId());
  // start drop of index triggers
  DropTrigReq* const req = (DropTrigReq*)signal->getDataPtrSend();
  req->setUserRef(reference());
  req->setConnectionPtr(opPtr.p->key);
  req->setRequestType(DropTrigReq::RT_ALTER_INDEX);
  req->setTableId(opPtr.p->m_request.getTableId());
  req->setIndexId(opPtr.p->m_request.getIndexId());
  req->setTriggerInfo(0);       // not used
  opPtr.p->m_triggerCounter = 0;
  // insert
  if (indexPtr.p->insertTriggerId != RNIL) {
    req->setTriggerId(indexPtr.p->insertTriggerId);
    sendSignal(reference(), GSN_DROP_TRIG_REQ, 
        signal, DropTrigReq::SignalLength, JBB);
    opPtr.p->m_triggerCounter++;
  }
  // update
  if (indexPtr.p->updateTriggerId != RNIL) {
    req->setTriggerId(indexPtr.p->updateTriggerId);
    sendSignal(reference(), GSN_DROP_TRIG_REQ, 
        signal, DropTrigReq::SignalLength, JBB);
    opPtr.p->m_triggerCounter++;
  }
  // delete
  if (indexPtr.p->deleteTriggerId != RNIL) {
    req->setTriggerId(indexPtr.p->deleteTriggerId);
    sendSignal(reference(), GSN_DROP_TRIG_REQ, 
        signal, DropTrigReq::SignalLength, JBB);
    opPtr.p->m_triggerCounter++;
  }
  // custom
  if (indexPtr.p->customTriggerId != RNIL) {
    req->setTriggerId(indexPtr.p->customTriggerId);
    sendSignal(reference(), GSN_DROP_TRIG_REQ, 
        signal, DropTrigReq::SignalLength, JBB);
    opPtr.p->m_triggerCounter++;
  }
  // build
  if (indexPtr.p->buildTriggerId != RNIL) {
    req->setTriggerId(indexPtr.p->buildTriggerId);
    sendSignal(reference(), GSN_DROP_TRIG_REQ, 
        signal, DropTrigReq::SignalLength, JBB);
    opPtr.p->m_triggerCounter++;
  }
  if (opPtr.p->m_triggerCounter == 0) {
    // drop in each TC
    jam();
    opPtr.p->m_requestType = AlterIndxReq::RT_DICT_TC;
    alterIndex_sendSlaveReq(signal, opPtr);
  }
}

void
Dbdict::alterIndex_fromDropTrigger(Signal* signal, OpAlterIndexPtr opPtr)
{
  jam();
  ndbrequire(opPtr.p->m_triggerCounter != 0);
  if (--opPtr.p->m_triggerCounter != 0) {
    jam();
    return;
  }
  // finally drop index in each TC
  TableRecordPtr indexPtr;
  c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId());
  const bool isHashIndex = indexPtr.p->isHashIndex();
  const bool isOrderedIndex = indexPtr.p->isOrderedIndex();
  ndbrequire(isHashIndex != isOrderedIndex);    // xor
  if (isHashIndex)
    opPtr.p->m_requestType = AlterIndxReq::RT_DICT_TC;
  if (isOrderedIndex)
    opPtr.p->m_requestType = AlterIndxReq::RT_DICT_COMMIT;
  alterIndex_sendSlaveReq(signal, opPtr);
}

void
Dbdict::alterIndex_toBuildIndex(Signal* signal, OpAlterIndexPtr opPtr)
{
  jam();
  // get index and table records
  TableRecordPtr indexPtr;
  c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId());
  TableRecordPtr tablePtr;
  c_tableRecordPool.getPtr(tablePtr, indexPtr.p->primaryTableId);
  // build request to self (short signal)
  BuildIndxReq* const req = (BuildIndxReq*)signal->getDataPtrSend();
  req->setUserRef(reference());
  req->setConnectionPtr(opPtr.p->key);
  req->setRequestType(BuildIndxReq::RT_ALTER_INDEX);
  req->addRequestFlag(opPtr.p->m_requestFlag);
  req->setBuildId(0);   // not used
  req->setBuildKey(0);  // not used
  req->setIndexType(indexPtr.p->tableType);
  req->setIndexId(indexPtr.i);
  req->setTableId(indexPtr.p->primaryTableId);
  req->setParallelism(16);
  // send
  sendSignal(reference(), GSN_BUILDINDXREQ,
      signal, BuildIndxReq::SignalLength, JBB);
}

void
Dbdict::alterIndex_fromBuildIndex(Signal* signal, OpAlterIndexPtr opPtr)
{
  jam();
  if (opPtr.p->hasError()) {
    jam();
    opPtr.p->m_requestType = AlterIndxReq::RT_DICT_ABORT;
    alterIndex_sendSlaveReq(signal, opPtr);
    return;
  }
  opPtr.p->m_requestType = AlterIndxReq::RT_DICT_COMMIT;
  alterIndex_sendSlaveReq(signal, opPtr);
}

void
Dbdict::alterIndex_slaveCommit(Signal* signal, OpAlterIndexPtr opPtr)
{
  jam();
  // get index record
  TableRecordPtr indexPtr;
  c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId());
  indexPtr.p->indexState = TableRecord::IS_ONLINE;
}

void
Dbdict::alterIndex_slaveAbort(Signal* signal, OpAlterIndexPtr opPtr)
{
  jam();
  // find index record
  const Uint32 indexId = opPtr.p->m_request.getIndexId();
  if (indexId >= c_tableRecordPool.getSize())
    return;
  TableRecordPtr indexPtr;
  c_tableRecordPool.getPtr(indexPtr, indexId);
  if (! indexPtr.p->isIndex())
    return;
  // mark broken
  indexPtr.p->indexState = TableRecord::IS_BROKEN;
}

void
Dbdict::alterIndex_sendSlaveReq(Signal* signal, OpAlterIndexPtr opPtr)
{
  AlterIndxReq* const req = (AlterIndxReq*)signal->getDataPtrSend();
  *req = opPtr.p->m_request;
  req->setUserRef(opPtr.p->m_coordinatorRef);
  req->setConnectionPtr(opPtr.p->key);
  req->setRequestType(opPtr.p->m_requestType);
  req->addRequestFlag(opPtr.p->m_requestFlag);
  NdbNodeBitmask receiverNodes = c_aliveNodes;
  if (opPtr.p->m_requestFlag & RequestFlag::RF_LOCAL) {
    receiverNodes.clear();
    receiverNodes.set(getOwnNodeId());
  }
  opPtr.p->m_signalCounter = receiverNodes;
  NodeReceiverGroup rg(DBDICT, receiverNodes);
  sendSignal(rg, GSN_ALTER_INDX_REQ,
      signal, AlterIndxReq::SignalLength, JBB);
}

void
Dbdict::alterIndex_sendReply(Signal* signal, OpAlterIndexPtr opPtr,
    bool toUser)
{
  AlterIndxRef* rep = (AlterIndxRef*)signal->getDataPtrSend();
  Uint32 gsn = GSN_ALTER_INDX_CONF;
  Uint32 length = AlterIndxConf::InternalLength;
  bool sendRef = opPtr.p->hasError();
  if (! toUser) {
    rep->setUserRef(opPtr.p->m_coordinatorRef);
    rep->setConnectionPtr(opPtr.p->key);
    rep->setRequestType(opPtr.p->m_requestType);
    if (opPtr.p->m_requestType == AlterIndxReq::RT_DICT_ABORT)
      sendRef = false;
  } else {
    rep->setUserRef(opPtr.p->m_request.getUserRef());
    rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr());
    rep->setRequestType(opPtr.p->m_request.getRequestType());
    length = AlterIndxConf::SignalLength;
  }
  rep->setTableId(opPtr.p->m_request.getTableId());
  rep->setIndexId(opPtr.p->m_request.getIndexId());
  if (sendRef) {
    if (opPtr.p->m_errorNode == 0)
      opPtr.p->m_errorNode = getOwnNodeId();
    rep->setErrorCode(opPtr.p->m_errorCode);
    rep->setErrorLine(opPtr.p->m_errorLine);
    rep->setErrorNode(opPtr.p->m_errorNode);
    gsn = GSN_ALTER_INDX_REF;
    length = AlterIndxRef::SignalLength;
  }
  sendSignal(rep->getUserRef(), gsn, signal, length, JBB);
}

/**
 * MODULE: Build index
 *
 * Build index or all indexes on a table.  Request type:
 *
 * RT_USER - normal user request, not yet used
 * RT_ALTER_INDEX - from alter index
 * RT_SYSTEM_RESTART - 
 * RT_DICT_PREPARE - prepare participants
 * RT_DICT_TRIX - to participant on way to local TRIX
 * RT_DICT_COMMIT - commit in each participant
 * RT_DICT_ABORT - abort
 * RT_TRIX - to local TRIX
 */

void
Dbdict::execBUILDINDXREQ(Signal* signal)
{
  jamEntry();
  BuildIndxReq* const req = (BuildIndxReq*)signal->getDataPtrSend();
  OpBuildIndexPtr opPtr;
  const Uint32 senderRef = signal->senderBlockRef();
  const BuildIndxReq::RequestType requestType = req->getRequestType();
  if (requestType == BuildIndxReq::RT_USER ||
      requestType == BuildIndxReq::RT_ALTER_INDEX ||
      requestType == BuildIndxReq::RT_SYSTEMRESTART) {
    jam();
    if (signal->getLength() == BuildIndxReq::SignalLength) {
      jam();
      if (getOwnNodeId() != c_masterNodeId) {
        jam();
        // forward to DICT master
        sendSignal(calcDictBlockRef(c_masterNodeId), GSN_BUILDINDXREQ,
            signal, signal->getLength(), JBB);
        return;
      }
      // forward initial request plus operation key to all
      req->setOpKey(++c_opRecordSequence);
      NodeReceiverGroup rg(DBDICT, c_aliveNodes);
      sendSignal(rg, GSN_BUILDINDXREQ,
          signal, BuildIndxReq::SignalLength + 1, JBB);
      return;
    }
    // seize operation record
    ndbrequire(signal->getLength() == BuildIndxReq::SignalLength + 1);
    const Uint32 opKey = req->getOpKey();
    OpBuildIndex opBusy;
    if (! c_opBuildIndex.seize(opPtr))
      opPtr.p = &opBusy;
    opPtr.p->save(req);
    opPtr.p->m_coordinatorRef = senderRef;
    opPtr.p->m_isMaster = (senderRef == reference());
    opPtr.p->key = opKey;
    opPtr.p->m_requestType = BuildIndxReq::RT_DICT_PREPARE;
    if (opPtr.p == &opBusy) {
      jam();
      opPtr.p->m_errorCode = BuildIndxRef::Busy;
      opPtr.p->m_errorLine = __LINE__;
      buildIndex_sendReply(signal, opPtr, opPtr.p->m_isMaster);
      return;
    }
    c_opBuildIndex.add(opPtr);
    // master expects to hear from all
    opPtr.p->m_signalCounter = c_aliveNodes;
    buildIndex_sendReply(signal, opPtr, false);
    return;
  }
  c_opBuildIndex.find(opPtr, req->getConnectionPtr());
  if (! opPtr.isNull()) {
    opPtr.p->m_requestType = requestType;
    if (requestType == BuildIndxReq::RT_DICT_TRIX) {
      jam();
      buildIndex_buildTrix(signal, opPtr);
      return;
    }
    if (requestType == BuildIndxReq::RT_DICT_TC ||
        requestType == BuildIndxReq::RT_DICT_TUX) {
      jam();
      buildIndex_toOnline(signal, opPtr);
      return;
    }
    if (requestType == BuildIndxReq::RT_DICT_COMMIT ||
        requestType == BuildIndxReq::RT_DICT_ABORT) {
      jam();
      buildIndex_sendReply(signal, opPtr, false);
      // done in slave
      if (! opPtr.p->m_isMaster)
        c_opBuildIndex.release(opPtr);
      return;
    }
  }
  jam();
  // return to sender
  OpBuildIndex opBad;
  opPtr.p = &opBad;
  opPtr.p->save(req);
  opPtr.p->m_errorCode = BuildIndxRef::BadRequestType;
  opPtr.p->m_errorLine = __LINE__;
  buildIndex_sendReply(signal, opPtr, true);
}

void
Dbdict::execBUILDINDXCONF(Signal* signal)
{
  jamEntry();
  ndbrequire(signal->getNoOfSections() == 0);
  BuildIndxConf* conf = (BuildIndxConf*)signal->getDataPtrSend();
  buildIndex_recvReply(signal, conf, 0);
}

void
Dbdict::execBUILDINDXREF(Signal* signal)
{
  jamEntry();
  BuildIndxRef* ref = (BuildIndxRef*)signal->getDataPtrSend();
  buildIndex_recvReply(signal, ref->getConf(), ref);
}

void
Dbdict::buildIndex_recvReply(Signal* signal, const BuildIndxConf* conf,
    const BuildIndxRef* ref)
{
  jam();
  const Uint32 senderRef = signal->senderBlockRef();
  const BuildIndxReq::RequestType requestType = conf->getRequestType();
  const Uint32 key = conf->getConnectionPtr();
  if (requestType == BuildIndxReq::RT_ALTER_INDEX) {
    jam();
    // part of alter index operation
    OpAlterIndexPtr opPtr;
    c_opAlterIndex.find(opPtr, key);
    ndbrequire(! opPtr.isNull());
    opPtr.p->setError(ref);
    alterIndex_fromBuildIndex(signal, opPtr);
    return;
  }

  if (requestType == BuildIndxReq::RT_SYSTEMRESTART) {
    jam();
    if (ref == 0) {
      infoEvent("DICT: index %u rebuild done", (unsigned)key);
    } else {
      warningEvent("DICT: index %u rebuild failed: code=%d line=%d node=%d",
		   (unsigned)key, ref->getErrorCode());
    }
    rebuildIndexes(signal, key + 1);
    return;
  }

  OpBuildIndexPtr opPtr;
  c_opBuildIndex.find(opPtr, key);
  ndbrequire(! opPtr.isNull());
  opPtr.p->setError(ref);
  if (requestType == BuildIndxReq::RT_TRIX) {
    jam();
    // forward to master
    opPtr.p->m_requestType = BuildIndxReq::RT_DICT_TRIX;
    buildIndex_sendReply(signal, opPtr, false);
    return;
  }
  ndbrequire(opPtr.p->m_isMaster);
  ndbrequire(opPtr.p->m_requestType == requestType);
  opPtr.p->m_signalCounter.clearWaitingFor(refToNode(senderRef));
  if (! opPtr.p->m_signalCounter.done()) {
    jam();
    return;
  }
  if (requestType == BuildIndxReq::RT_DICT_COMMIT ||
      requestType == BuildIndxReq::RT_DICT_ABORT) {
    jam();
    // send reply to user
    buildIndex_sendReply(signal, opPtr, true);
    c_opBuildIndex.release(opPtr);
    return;
  }
  if (opPtr.p->hasError()) {
    jam();
    opPtr.p->m_requestType = BuildIndxReq::RT_DICT_ABORT;
    buildIndex_sendSlaveReq(signal, opPtr);
    return;
  }
  TableRecordPtr indexPtr;
  c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId());
  if (indexPtr.p->isHashIndex()) {
    if (requestType == BuildIndxReq::RT_DICT_PREPARE) {
      jam();
      if (! (opPtr.p->m_requestFlag & RequestFlag::RF_NOBUILD)) {
        buildIndex_toCreateConstr(signal, opPtr);
      } else {
        opPtr.p->m_requestType = BuildIndxReq::RT_DICT_TC;
        buildIndex_sendSlaveReq(signal, opPtr);
      }
      return;
    }
    if (requestType == BuildIndxReq::RT_DICT_TRIX) {
      jam();
      ndbrequire(! (opPtr.p->m_requestFlag & RequestFlag::RF_NOBUILD));
      buildIndex_toDropConstr(signal, opPtr);
      return;
    }
    if (requestType == BuildIndxReq::RT_DICT_TC) {
      jam();
      opPtr.p->m_requestType = BuildIndxReq::RT_DICT_COMMIT;
      buildIndex_sendSlaveReq(signal, opPtr);
      return;
    }
  }
  if (indexPtr.p->isOrderedIndex()) {
    if (requestType == BuildIndxReq::RT_DICT_PREPARE) {
      jam();
      if (! (opPtr.p->m_requestFlag & RequestFlag::RF_NOBUILD)) {
        opPtr.p->m_requestType = BuildIndxReq::RT_DICT_TRIX;
        buildIndex_sendSlaveReq(signal, opPtr);
      } else {
        opPtr.p->m_requestType = BuildIndxReq::RT_DICT_TUX;
        buildIndex_sendSlaveReq(signal, opPtr);
      }
      return;
    }
    if (requestType == BuildIndxReq::RT_DICT_TRIX) {
      jam();
      ndbrequire(! (opPtr.p->m_requestFlag & RequestFlag::RF_NOBUILD));
      opPtr.p->m_requestType = BuildIndxReq::RT_DICT_TUX;
      buildIndex_sendSlaveReq(signal, opPtr);
      return;
    }
    if (requestType == BuildIndxReq::RT_DICT_TUX) {
      jam();
      opPtr.p->m_requestType = BuildIndxReq::RT_DICT_COMMIT;
      buildIndex_sendSlaveReq(signal, opPtr);
      return;
    }
  }
  ndbrequire(false);
} 

void
Dbdict::buildIndex_toCreateConstr(Signal* signal, OpBuildIndexPtr opPtr)
{
  jam();
  TableRecordPtr indexPtr;
  c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId());
  // request to create constraint trigger
  CreateTrigReq* req = (CreateTrigReq*)signal->getDataPtrSend();
  req->setUserRef(reference());
  req->setConnectionPtr(opPtr.p->key);
  req->setRequestType(CreateTrigReq::RT_BUILD_INDEX);
  req->addRequestFlag(0);       // none
  req->setTableId(indexPtr.i);
  req->setIndexId(RNIL);
  req->setTriggerId(RNIL);
  req->setTriggerType(TriggerType::READ_ONLY_CONSTRAINT);
  req->setTriggerActionTime(TriggerActionTime::TA_AFTER);
  req->setTriggerEvent(TriggerEvent::TE_UPDATE);
  req->setMonitorReplicas(false);
  req->setMonitorAllAttributes(false);
  req->setOnline(true);         // alter online after create
  req->setReceiverRef(0);       // no receiver, REF-ed by TUP
  req->getAttributeMask().clear();
  // NDB$PK is last attribute
  req->getAttributeMask().set(indexPtr.p->noOfAttributes - 1);
  // name section
  char triggerName[MAX_TAB_NAME_SIZE];
  Uint32 buffer[2 + ((MAX_TAB_NAME_SIZE + 3) >> 2)];    // SP string
  LinearWriter w(buffer, sizeof(buffer) >> 2);
  LinearSectionPtr lsPtr[3];
  sprintf(triggerName, "NDB$INDEX_%u_BUILD", indexPtr.i);
  w.reset();
  w.add(CreateTrigReq::TriggerNameKey, triggerName);
  lsPtr[0].p = buffer;
  lsPtr[0].sz = w.getWordsUsed();
  sendSignal(reference(), GSN_CREATE_TRIG_REQ,
      signal, CreateTrigReq::SignalLength, JBB, lsPtr, 1);
}

void
Dbdict::buildIndex_fromCreateConstr(Signal* signal, OpBuildIndexPtr opPtr)
{
  jam();
  if (opPtr.p->hasError()) {
    jam();
    opPtr.p->m_requestType = BuildIndxReq::RT_DICT_ABORT;
    buildIndex_sendSlaveReq(signal, opPtr);
    return;
  }
  opPtr.p->m_requestType = BuildIndxReq::RT_DICT_TRIX;
  buildIndex_sendSlaveReq(signal, opPtr);
}

void
Dbdict::buildIndex_buildTrix(Signal* signal, OpBuildIndexPtr opPtr)
{
  jam();
  TableRecordPtr indexPtr;
  c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId());
  TableRecordPtr tablePtr;
  c_tableRecordPool.getPtr(tablePtr, indexPtr.p->primaryTableId);
  // build request
  BuildIndxReq* const req = (BuildIndxReq*)signal->getDataPtrSend();
  req->setUserRef(reference());
  req->setConnectionPtr(opPtr.p->key);
  req->setRequestType(BuildIndxReq::RT_TRIX);
  req->setBuildId(0);   // not yet..
  req->setBuildKey(0);  // ..in use
  req->setIndexType(indexPtr.p->tableType);
  req->setIndexId(indexPtr.i);
  req->setTableId(indexPtr.p->primaryTableId);
  req->setParallelism(16);
  if (indexPtr.p->isHashIndex()) {
    jam();
    getIndexAttrList(indexPtr, opPtr.p->m_attrList);
    getTableKeyList(tablePtr, opPtr.p->m_tableKeyList);
    // send
    LinearSectionPtr lsPtr[3];
    lsPtr[0].sz = opPtr.p->m_attrList.sz;
    lsPtr[0].p = opPtr.p->m_attrList.id;
    lsPtr[1].sz = opPtr.p->m_tableKeyList.sz;
    lsPtr[1].p = opPtr.p->m_tableKeyList.id;
    sendSignal(calcTrixBlockRef(getOwnNodeId()), GSN_BUILDINDXREQ,
        signal, BuildIndxReq::SignalLength, JBB, lsPtr, 2);
    return;
  }
  if (indexPtr.p->isOrderedIndex()) {
    jam();
    sendSignal(calcTupBlockRef(getOwnNodeId()), GSN_BUILDINDXREQ,
        signal, BuildIndxReq::SignalLength, JBB);
    return;
  }
  ndbrequire(false);
}

void
Dbdict::buildIndex_toDropConstr(Signal* signal, OpBuildIndexPtr opPtr)
{
  jam();
  TableRecordPtr indexPtr;
  c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId());
  // request to drop constraint trigger
  DropTrigReq* req = (DropTrigReq*)signal->getDataPtrSend();
  req->setUserRef(reference());
  req->setConnectionPtr(opPtr.p->key);
  req->setRequestType(DropTrigReq::RT_BUILD_INDEX);
  req->addRequestFlag(0);       // none
  req->setTableId(indexPtr.i);
  req->setIndexId(RNIL);
  req->setTriggerId(opPtr.p->m_constrTriggerId);
  req->setTriggerInfo(0);       // not used
  sendSignal(reference(), GSN_DROP_TRIG_REQ,
      signal, DropTrigReq::SignalLength, JBB);
}

void
Dbdict::buildIndex_fromDropConstr(Signal* signal, OpBuildIndexPtr opPtr)
{
  jam();
  if (opPtr.p->hasError()) {
    jam();
    opPtr.p->m_requestType = BuildIndxReq::RT_DICT_ABORT;
    buildIndex_sendSlaveReq(signal, opPtr);
    return;
  }
  opPtr.p->m_requestType = BuildIndxReq::RT_DICT_TC;
  buildIndex_sendSlaveReq(signal, opPtr);
}

void
Dbdict::buildIndex_toOnline(Signal* signal, OpBuildIndexPtr opPtr)
{
  jam();
  TableRecordPtr indexPtr;
  c_tableRecordPool.getPtr(indexPtr, opPtr.p->m_request.getIndexId());
  TableRecordPtr tablePtr;
  c_tableRecordPool.getPtr(tablePtr, indexPtr.p->primaryTableId);
  // request to set index online in TC or TUX
  AlterIndxReq* const req = (AlterIndxReq*)signal->getDataPtrSend();
  req->setUserRef(reference());
  req->setConnectionPtr(opPtr.p->key);
  if (opPtr.p->m_requestType == BuildIndxReq::RT_DICT_TC) {
    req->setRequestType(AlterIndxReq::RT_TC);
  } else if (opPtr.p->m_requestType == BuildIndxReq::RT_DICT_TUX) {
    req->setRequestType(AlterIndxReq::RT_TUX);
  } else {
    ndbrequire(false);
  }
  req->setTableId(tablePtr.i);
  req->setIndexId(indexPtr.i);
  req->setIndexVersion(indexPtr.p->tableVersion);
  req->setOnline(true);
  BlockReference blockRef = 0;
  if (opPtr.p->m_requestType == BuildIndxReq::RT_DICT_TC) {
    blockRef = calcTcBlockRef(getOwnNodeId());
  } else if (opPtr.p->m_requestType == BuildIndxReq::RT_DICT_TUX) {
    blockRef = calcTuxBlockRef(getOwnNodeId());
  } else {
    ndbrequire(false);
  }
  // send
  sendSignal(blockRef, GSN_ALTER_INDX_REQ,
      signal, BuildIndxReq::SignalLength, JBB);
}

void
Dbdict::buildIndex_fromOnline(Signal* signal, OpBuildIndexPtr opPtr)
{
  jam();
  // forward to master
  buildIndex_sendReply(signal, opPtr, false);
}

void
Dbdict::buildIndex_sendSlaveReq(Signal* signal, OpBuildIndexPtr opPtr)
{
  BuildIndxReq* const req = (BuildIndxReq*)signal->getDataPtrSend();
  *req = opPtr.p->m_request;
  req->setUserRef(opPtr.p->m_coordinatorRef);
  req->setConnectionPtr(opPtr.p->key);
  req->setRequestType(opPtr.p->m_requestType);
  req->addRequestFlag(opPtr.p->m_requestFlag);
  opPtr.p->m_signalCounter = c_aliveNodes;
  NodeReceiverGroup rg(DBDICT, c_aliveNodes);
  sendSignal(rg, GSN_BUILDINDXREQ,
      signal, BuildIndxReq::SignalLength, JBB);
}

void
Dbdict::buildIndex_sendReply(Signal* signal, OpBuildIndexPtr opPtr,
    bool toUser)
{
  BuildIndxRef* rep = (BuildIndxRef*)signal->getDataPtrSend();
  Uint32 gsn = GSN_BUILDINDXCONF;
  Uint32 length = BuildIndxConf::InternalLength;
  bool sendRef = opPtr.p->hasError();
  if (! toUser) {
    rep->setUserRef(opPtr.p->m_coordinatorRef);
    rep->setConnectionPtr(opPtr.p->key);
    rep->setRequestType(opPtr.p->m_requestType);
    if (opPtr.p->m_requestType == BuildIndxReq::RT_DICT_ABORT)
      sendRef = false;
  } else {
    rep->setUserRef(opPtr.p->m_request.getUserRef());
    rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr());
    rep->setRequestType(opPtr.p->m_request.getRequestType());
    length = BuildIndxConf::SignalLength;
  }
  rep->setIndexType(opPtr.p->m_request.getIndexType());
  rep->setTableId(opPtr.p->m_request.getTableId());
  rep->setIndexId(opPtr.p->m_request.getIndexId());
  if (sendRef) {
    rep->setErrorCode(opPtr.p->m_errorCode);
    gsn = GSN_BUILDINDXREF;
    length = BuildIndxRef::SignalLength;
  }
  sendSignal(rep->getUserRef(), gsn, signal, length, JBB);
}

/**
 * MODULE: Create trigger
 *
 * Create trigger in all DICT blocks.  Optionally start alter trigger
 * operation to set the trigger online.
 *
 * Request type received in REQ and returned in CONF/REF:
 *
 * RT_USER - normal user e.g. BACKUP
 * RT_ALTER_INDEX - from alter index online
 * RT_DICT_PREPARE - seize operation in each DICT
 * RT_DICT_COMMIT - commit create in each DICT
 * RT_TC - sending to TC (operation alter trigger)
 * RT_LQH - sending to LQH (operation alter trigger)
 */

void
Dbdict::execCREATE_TRIG_REQ(Signal* signal) 
{
  jamEntry();
  CreateTrigReq* const req = (CreateTrigReq*)signal->getDataPtrSend();
  OpCreateTriggerPtr opPtr;
  const Uint32 senderRef = signal->senderBlockRef();
  const CreateTrigReq::RequestType requestType = req->getRequestType();
  if (requestType == CreateTrigReq::RT_USER ||
      requestType == CreateTrigReq::RT_ALTER_INDEX ||
      requestType == CreateTrigReq::RT_BUILD_INDEX) {
    jam();
    if (! assembleFragments(signal)) {
      jam();
      return;
    }
    const bool isLocal = req->getRequestFlag() & RequestFlag::RF_LOCAL;
    NdbNodeBitmask receiverNodes = c_aliveNodes;
    if (isLocal) {
      receiverNodes.clear();
      receiverNodes.set(getOwnNodeId());
    }
    if (signal->getLength() == CreateTrigReq::SignalLength) {
      jam();
      if (! isLocal && getOwnNodeId() != c_masterNodeId) {
        jam();
        // forward to DICT master
        sendSignal(calcDictBlockRef(c_masterNodeId), GSN_CREATE_TRIG_REQ,
            signal, signal->getLength(), JBB);
        return;
      }
      // forward initial request plus operation key to all
      req->setOpKey(++c_opRecordSequence);
      NodeReceiverGroup rg(DBDICT, receiverNodes);
      sendSignal(rg, GSN_CREATE_TRIG_REQ,
          signal, CreateTrigReq::SignalLength + 1, JBB);
      return;
    }
    // seize operation record
    ndbrequire(signal->getLength() == CreateTrigReq::SignalLength + 1);
    const Uint32 opKey = req->getOpKey();
    OpCreateTrigger opBusy;
    if (! c_opCreateTrigger.seize(opPtr))
      opPtr.p = &opBusy;
    opPtr.p->save(req);
    opPtr.p->m_coordinatorRef = senderRef;
    opPtr.p->m_isMaster = (senderRef == reference());
    opPtr.p->key = opKey;
    opPtr.p->m_requestType = CreateTrigReq::RT_DICT_PREPARE;
    if (opPtr.p == &opBusy) {
      jam();
      opPtr.p->m_errorCode = CreateTrigRef::Busy;
      opPtr.p->m_errorLine = __LINE__;
      releaseSections(signal);
      createTrigger_sendReply(signal, opPtr, opPtr.p->m_isMaster);
      return;
    }
    c_opCreateTrigger.add(opPtr);
    {
      // save name
      SegmentedSectionPtr ssPtr;
      signal->getSection(ssPtr, CreateTrigReq::TRIGGER_NAME_SECTION);
      SimplePropertiesSectionReader ssReader(ssPtr, getSectionSegmentPool());
      if (ssReader.getKey() != CreateTrigReq::TriggerNameKey ||
	  ! ssReader.getString(opPtr.p->m_triggerName)) {
	jam();
	opPtr.p->m_errorCode = CreateTrigRef::InvalidName;
	opPtr.p->m_errorLine = __LINE__;
	releaseSections(signal);
	createTrigger_sendReply(signal, opPtr, opPtr.p->m_isMaster);
	return;
      }
    }
    releaseSections(signal);
    {
      // check that trigger name is unique
      TriggerRecordPtr triggerPtr;
      TriggerRecord keyRecord;
      strcpy(keyRecord.triggerName, opPtr.p->m_triggerName);
      c_triggerRecordHash.find(triggerPtr, keyRecord);
      if (triggerPtr.i != RNIL) {
	jam();
	opPtr.p->m_errorCode = CreateTrigRef::TriggerExists;
	opPtr.p->m_errorLine = __LINE__;
	createTrigger_sendReply(signal, opPtr, opPtr.p->m_isMaster);
	return;
      }
    }

    // master expects to hear from all
    if (opPtr.p->m_isMaster)
      opPtr.p->m_signalCounter = receiverNodes;
    // check request in all participants
    createTrigger_slavePrepare(signal, opPtr);
    createTrigger_sendReply(signal, opPtr, false);
    return;
  }
  c_opCreateTrigger.find(opPtr, req->getConnectionPtr());
  if (! opPtr.isNull()) {
    opPtr.p->m_requestType = requestType;
    if (requestType == CreateTrigReq::RT_DICT_CREATE) {
      jam();
      // master has set trigger id
      opPtr.p->m_request.setTriggerId(req->getTriggerId());
      createTrigger_slaveCreate(signal, opPtr);
      createTrigger_sendReply(signal, opPtr, false);
      return;
    }
    if (requestType == CreateTrigReq::RT_DICT_COMMIT ||
        requestType == CreateTrigReq::RT_DICT_ABORT) {
      jam();
      if (requestType == CreateTrigReq::RT_DICT_COMMIT)
        createTrigger_slaveCommit(signal, opPtr);
      else
        createTrigger_slaveAbort(signal, opPtr);
      createTrigger_sendReply(signal, opPtr, false);
      // done in slave
      if (! opPtr.p->m_isMaster)
        c_opCreateTrigger.release(opPtr);
      return;
    }
  }
  jam();
  // return to sender
  releaseSections(signal);
  OpCreateTrigger opBad;
  opPtr.p = &opBad;
  opPtr.p->save(req);
  opPtr.p->m_errorCode = CreateTrigRef::BadRequestType;
  opPtr.p->m_errorLine = __LINE__;
  createTrigger_sendReply(signal,  opPtr, true);
}

void
Dbdict::execCREATE_TRIG_CONF(Signal* signal) 
{
  jamEntry();
  ndbrequire(signal->getNoOfSections() == 0);
  CreateTrigConf* conf = (CreateTrigConf*)signal->getDataPtrSend();
  createTrigger_recvReply(signal, conf, 0);
}

void
Dbdict::execCREATE_TRIG_REF(Signal* signal) 
{
  jamEntry();
  CreateTrigRef* ref = (CreateTrigRef*)signal->getDataPtrSend();
  createTrigger_recvReply(signal, ref->getConf(), ref);
}

void
Dbdict::createTrigger_recvReply(Signal* signal, const CreateTrigConf* conf,
    const CreateTrigRef* ref)
{
  jam();
  const Uint32 senderRef = signal->senderBlockRef();
  const CreateTrigReq::RequestType requestType = conf->getRequestType();
  const Uint32 key = conf->getConnectionPtr();
  if (requestType == CreateTrigReq::RT_ALTER_INDEX) {
    jam();
    // part of alter index operation
    OpAlterIndexPtr opPtr;
    c_opAlterIndex.find(opPtr, key);
    ndbrequire(! opPtr.isNull());
    opPtr.p->setError(ref);
    alterIndex_fromCreateTrigger(signal, opPtr);
    return;
  }
  if (requestType == CreateTrigReq::RT_BUILD_INDEX) {
    jam();
    // part of build index operation
    OpBuildIndexPtr opPtr;
    c_opBuildIndex.find(opPtr, key);
    ndbrequire(! opPtr.isNull());
    opPtr.p->setError(ref);
    // fill in trigger id
    opPtr.p->m_constrTriggerId = conf->getTriggerId();
    buildIndex_fromCreateConstr(signal, opPtr);
    return;
  }
  if (requestType == CreateTrigReq::RT_TC ||
      requestType == CreateTrigReq::RT_LQH) {
    jam();
    // part of alter trigger operation
    OpAlterTriggerPtr opPtr;
    c_opAlterTrigger.find(opPtr, key);
    ndbrequire(! opPtr.isNull());
    opPtr.p->setError(ref);
    alterTrigger_fromCreateLocal(signal, opPtr);
    return;
  }
  OpCreateTriggerPtr opPtr;
  c_opCreateTrigger.find(opPtr, key);
  ndbrequire(! opPtr.isNull());
  ndbrequire(opPtr.p->m_isMaster);
  ndbrequire(opPtr.p->m_requestType == requestType);
  opPtr.p->setError(ref);
  opPtr.p->m_signalCounter.clearWaitingFor(refToNode(senderRef));
  if (! opPtr.p->m_signalCounter.done()) {
    jam();
    return;
  }
  if (requestType == CreateTrigReq::RT_DICT_COMMIT ||
      requestType == CreateTrigReq::RT_DICT_ABORT) {
    jam();
    // send reply to user
    createTrigger_sendReply(signal, opPtr, true);
    c_opCreateTrigger.release(opPtr);
    return;
  }
  if (opPtr.p->hasError()) {
    jam();
    opPtr.p->m_requestType = CreateTrigReq::RT_DICT_ABORT;
    createTrigger_sendSlaveReq(signal, opPtr);
    return;
  }
  if (requestType == CreateTrigReq::RT_DICT_PREPARE) {
    jam();
    // seize trigger id in master
    createTrigger_masterSeize(signal, opPtr);
    if (opPtr.p->hasError()) {
      jam();
      opPtr.p->m_requestType = CreateTrigReq::RT_DICT_ABORT;
      createTrigger_sendSlaveReq(signal, opPtr);
      return;
    }
    opPtr.p->m_requestType = CreateTrigReq::RT_DICT_CREATE;
    createTrigger_sendSlaveReq(signal, opPtr);
    return;
  }
  if (requestType == CreateTrigReq::RT_DICT_CREATE) {
    jam();
    if (opPtr.p->m_request.getOnline()) {
      jam();
      // start alter online
      createTrigger_toAlterTrigger(signal, opPtr);
      return;
    }
    opPtr.p->m_requestType = CreateTrigReq::RT_DICT_COMMIT;
    createTrigger_sendSlaveReq(signal, opPtr);
    return;
  }
  ndbrequire(false);
}

void
Dbdict::createTrigger_slavePrepare(Signal* signal, OpCreateTriggerPtr opPtr)
{
  jam();
  const CreateTrigReq* const req = &opPtr.p->m_request;
  // check trigger type
  if (req->getRequestType() == CreateTrigReq::RT_USER &&
      req->getTriggerType() == TriggerType::SUBSCRIPTION ||
      req->getRequestType() == CreateTrigReq::RT_ALTER_INDEX &&
      req->getTriggerType() == TriggerType::SECONDARY_INDEX ||
      req->getRequestType() == CreateTrigReq::RT_ALTER_INDEX &&
      req->getTriggerType() == TriggerType::ORDERED_INDEX ||
      req->getRequestType() == CreateTrigReq::RT_BUILD_INDEX &&
      req->getTriggerType() == TriggerType::READ_ONLY_CONSTRAINT) {
    ;
  } else {
    jam();
    opPtr.p->m_errorCode = CreateTrigRef::UnsupportedTriggerType;
    opPtr.p->m_errorLine = __LINE__;
    return;
  }
  // check the table
  const Uint32 tableId = req->getTableId();
  if (! (tableId < c_tableRecordPool.getSize())) {
    jam();
    opPtr.p->m_errorCode = CreateTrigRef::InvalidTable;
    opPtr.p->m_errorLine = __LINE__;
    return;
  }
  TableRecordPtr tablePtr;
  c_tableRecordPool.getPtr(tablePtr, tableId);
  if (tablePtr.p->tabState != TableRecord::DEFINED) {
    jam();
    opPtr.p->m_errorCode = CreateTrigRef::InvalidTable;
    opPtr.p->m_errorLine = __LINE__;
    return;
  }
}

void
Dbdict::createTrigger_masterSeize(Signal* signal, OpCreateTriggerPtr opPtr)
{
  TriggerRecordPtr triggerPtr;
  if (opPtr.p->m_requestFlag & RequestFlag::RF_LOCAL) {
    triggerPtr.i = opPtr.p->m_request.getTriggerId();
  } else {
    triggerPtr.i = getFreeTriggerRecord();
    if (triggerPtr.i == RNIL) {
      jam();
      opPtr.p->m_errorCode = CreateTrigRef::TooManyTriggers;
      opPtr.p->m_errorLine = __LINE__;
      return;
    }
  }
  c_triggerRecordPool.getPtr(triggerPtr);
  initialiseTriggerRecord(triggerPtr);
  triggerPtr.p->triggerState = TriggerRecord::TS_DEFINING;
  opPtr.p->m_request.setTriggerId(triggerPtr.i);
}

void
Dbdict::createTrigger_slaveCreate(Signal* signal, OpCreateTriggerPtr opPtr)
{
  jam();
  const CreateTrigReq* const req = &opPtr.p->m_request;
  // get the trigger record
  const Uint32 triggerId = req->getTriggerId();
  TriggerRecordPtr triggerPtr;
  c_triggerRecordPool.getPtr(triggerPtr, triggerId);
  initialiseTriggerRecord(triggerPtr);
  // fill in trigger data
  strcpy(triggerPtr.p->triggerName, opPtr.p->m_triggerName);
  triggerPtr.p->triggerId = triggerId;
  triggerPtr.p->tableId = req->getTableId();
  triggerPtr.p->indexId = RNIL;
  triggerPtr.p->triggerType = req->getTriggerType();
  triggerPtr.p->triggerActionTime = req->getTriggerActionTime();
  triggerPtr.p->triggerEvent = req->getTriggerEvent();
  triggerPtr.p->monitorReplicas = req->getMonitorReplicas();
  triggerPtr.p->monitorAllAttributes = req->getMonitorAllAttributes();
  triggerPtr.p->attributeMask = req->getAttributeMask();
  triggerPtr.p->triggerState = TriggerRecord::TS_OFFLINE;
  // add to hash table
  //  ndbout_c("++++++++++++ Adding trigger id %u, %s", triggerPtr.p->triggerId, triggerPtr.p->triggerName);
  c_triggerRecordHash.add(triggerPtr);
  if (triggerPtr.p->triggerType == TriggerType::SECONDARY_INDEX ||
      triggerPtr.p->triggerType == TriggerType::ORDERED_INDEX) {
    jam();
    // connect to index record  XXX should be done in caller instead
    triggerPtr.p->indexId = req->getIndexId();
    TableRecordPtr indexPtr;
    c_tableRecordPool.getPtr(indexPtr, triggerPtr.p->indexId);
    switch (triggerPtr.p->triggerEvent) {
    case TriggerEvent::TE_INSERT:
      indexPtr.p->insertTriggerId = triggerPtr.p->triggerId;
      break;
    case TriggerEvent::TE_UPDATE:
      indexPtr.p->updateTriggerId = triggerPtr.p->triggerId;
      break;
    case TriggerEvent::TE_DELETE:
      indexPtr.p->deleteTriggerId = triggerPtr.p->triggerId;
      break;
    case TriggerEvent::TE_CUSTOM:
      indexPtr.p->customTriggerId = triggerPtr.p->triggerId;
      break;
    default:
      ndbrequire(false);
      break;
    }
  }
  if (triggerPtr.p->triggerType == TriggerType::READ_ONLY_CONSTRAINT) {
    jam();
    // connect to index record  XXX should be done in caller instead
    triggerPtr.p->indexId = req->getTableId();
    TableRecordPtr indexPtr;
    c_tableRecordPool.getPtr(indexPtr, triggerPtr.p->indexId);
    indexPtr.p->buildTriggerId = triggerPtr.p->triggerId;
  }
}

void
Dbdict::createTrigger_toAlterTrigger(Signal* signal, OpCreateTriggerPtr opPtr)
{
  jam();
  AlterTrigReq* req = (AlterTrigReq*)signal->getDataPtrSend();
  req->setUserRef(reference());
  req->setConnectionPtr(opPtr.p->key);
  req->setRequestType(AlterTrigReq::RT_CREATE_TRIGGER);
  req->addRequestFlag(opPtr.p->m_requestFlag);
  req->setTableId(opPtr.p->m_request.getTableId());
  req->setTriggerId(opPtr.p->m_request.getTriggerId());
  req->setTriggerInfo(0);       // not used
  req->setOnline(true);
  req->setReceiverRef(opPtr.p->m_request.getReceiverRef());
  sendSignal(reference(), GSN_ALTER_TRIG_REQ,
      signal, AlterTrigReq::SignalLength, JBB);
}

void
Dbdict::createTrigger_fromAlterTrigger(Signal* signal, OpCreateTriggerPtr opPtr)
{
  jam();
  if (opPtr.p->hasError()) {
    jam();
    opPtr.p->m_requestType = CreateTrigReq::RT_DICT_ABORT;
    createTrigger_sendSlaveReq(signal, opPtr);
    return;
  }
  opPtr.p->m_requestType = CreateTrigReq::RT_DICT_COMMIT;
  createTrigger_sendSlaveReq(signal, opPtr);
}

void
Dbdict::createTrigger_slaveCommit(Signal* signal, OpCreateTriggerPtr opPtr)
{
  jam();
  const CreateTrigReq* const req = &opPtr.p->m_request;
  // get the trigger record
  const Uint32 triggerId = req->getTriggerId();
  TriggerRecordPtr triggerPtr;
  c_triggerRecordPool.getPtr(triggerPtr, triggerId);
  if (! req->getOnline()) {
    triggerPtr.p->triggerState = TriggerRecord::TS_OFFLINE;
  } else {
    ndbrequire(triggerPtr.p->triggerState == TriggerRecord::TS_ONLINE);
  }
}

void
Dbdict::createTrigger_slaveAbort(Signal* signal, OpCreateTriggerPtr opPtr)
{
  jam();
}

void
Dbdict::createTrigger_sendSlaveReq(Signal* signal, OpCreateTriggerPtr opPtr)
{
  CreateTrigReq* const req = (CreateTrigReq*)signal->getDataPtrSend();
  *req = opPtr.p->m_request;
  req->setUserRef(opPtr.p->m_coordinatorRef);
  req->setConnectionPtr(opPtr.p->key);
  req->setRequestType(opPtr.p->m_requestType);
  req->addRequestFlag(opPtr.p->m_requestFlag);
  NdbNodeBitmask receiverNodes = c_aliveNodes;
  if (opPtr.p->m_requestFlag & RequestFlag::RF_LOCAL) {
    receiverNodes.clear();
    receiverNodes.set(getOwnNodeId());
  }
  opPtr.p->m_signalCounter = receiverNodes;
  NodeReceiverGroup rg(DBDICT, receiverNodes);
  sendSignal(rg, GSN_CREATE_TRIG_REQ,
      signal, CreateTrigReq::SignalLength, JBB);
}

void
Dbdict::createTrigger_sendReply(Signal* signal, OpCreateTriggerPtr opPtr,
    bool toUser)
{
  CreateTrigRef* rep = (CreateTrigRef*)signal->getDataPtrSend();
  Uint32 gsn = GSN_CREATE_TRIG_CONF;
  Uint32 length = CreateTrigConf::InternalLength;
  bool sendRef = opPtr.p->hasError();
  if (! toUser) {
    rep->setUserRef(opPtr.p->m_coordinatorRef);
    rep->setConnectionPtr(opPtr.p->key);
    rep->setRequestType(opPtr.p->m_requestType);
    if (opPtr.p->m_requestType == CreateTrigReq::RT_DICT_ABORT)
      sendRef = false;
  } else {
    rep->setUserRef(opPtr.p->m_request.getUserRef());
    rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr());
    rep->setRequestType(opPtr.p->m_request.getRequestType());
    length = CreateTrigConf::SignalLength;
  }
  rep->setTableId(opPtr.p->m_request.getTableId());
  rep->setIndexId(opPtr.p->m_request.getIndexId());
  rep->setTriggerId(opPtr.p->m_request.getTriggerId());
  rep->setTriggerInfo(opPtr.p->m_request.getTriggerInfo());
  if (sendRef) {
    if (opPtr.p->m_errorNode == 0)
      opPtr.p->m_errorNode = getOwnNodeId();
    rep->setErrorCode(opPtr.p->m_errorCode);
    rep->setErrorLine(opPtr.p->m_errorLine);
    rep->setErrorNode(opPtr.p->m_errorNode);
    gsn = GSN_CREATE_TRIG_REF;
    length = CreateTrigRef::SignalLength;
  }
  sendSignal(rep->getUserRef(), gsn, signal, length, JBB);
}

/**
 * MODULE: Drop trigger.
 */

void
Dbdict::execDROP_TRIG_REQ(Signal* signal) 
{
  jamEntry();
  DropTrigReq* const req = (DropTrigReq*)signal->getDataPtrSend();
  OpDropTriggerPtr opPtr;
  const Uint32 senderRef = signal->senderBlockRef();
  const DropTrigReq::RequestType requestType = req->getRequestType();

  if (signal->getNoOfSections() > 0) {
    ndbrequire(signal->getNoOfSections() == 1);
    jam();
    TriggerRecord keyRecord;
    OpDropTrigger opTmp;
    opPtr.p=&opTmp;

    SegmentedSectionPtr ssPtr;
    signal->getSection(ssPtr, DropTrigReq::TRIGGER_NAME_SECTION);
    SimplePropertiesSectionReader ssReader(ssPtr, getSectionSegmentPool());
    if (ssReader.getKey() != DropTrigReq::TriggerNameKey ||
	! ssReader.getString(keyRecord.triggerName)) {
      jam();
      opPtr.p->m_errorCode = DropTrigRef::InvalidName;
      opPtr.p->m_errorLine = __LINE__;
      releaseSections(signal);
      dropTrigger_sendReply(signal, opPtr, opPtr.p->m_isMaster);
      return;
    }
    releaseSections(signal);

    TriggerRecordPtr triggerPtr;

    //    ndbout_c("++++++++++++++ Looking for trigger %s", keyRecord.triggerName);
    c_triggerRecordHash.find(triggerPtr, keyRecord);
    if (triggerPtr.i == RNIL) {
      jam();
      req->setTriggerId(RNIL);
    } else {
      jam();
      //      ndbout_c("++++++++++ Found trigger %s", triggerPtr.p->triggerName);
      req->setTriggerId(triggerPtr.p->triggerId);
      req->setTableId(triggerPtr.p->tableId);
    }
  }
  if (requestType == DropTrigReq::RT_USER ||
      requestType == DropTrigReq::RT_ALTER_INDEX ||
      requestType == DropTrigReq::RT_BUILD_INDEX) {
    jam();
    if (signal->getLength() == DropTrigReq::SignalLength) {
      if (getOwnNodeId() != c_masterNodeId) {
	jam();
	// forward to DICT master
	sendSignal(calcDictBlockRef(c_masterNodeId), GSN_DROP_TRIG_REQ,
		   signal, signal->getLength(), JBB);
	return;
      }
      if (!c_triggerRecordPool.findId(req->getTriggerId())) {
	jam();
	// return to sender
	OpDropTrigger opBad;
	opPtr.p = &opBad;
	opPtr.p->save(req);
	opPtr.p->m_errorCode = DropTrigRef::TriggerNotFound;
	opPtr.p->m_errorLine = __LINE__;
	dropTrigger_sendReply(signal,  opPtr, true);
	return;
      }
      // forward initial request plus operation key to all
      req->setOpKey(++c_opRecordSequence);
      NodeReceiverGroup rg(DBDICT, c_aliveNodes);
      sendSignal(rg, GSN_DROP_TRIG_REQ,
		 signal, DropTrigReq::SignalLength + 1, JBB);
      return;
    }
    // seize operation record
    ndbrequire(signal->getLength() == DropTrigReq::SignalLength + 1);
    const Uint32 opKey = req->getOpKey();
    OpDropTrigger opBusy;
    if (! c_opDropTrigger.seize(opPtr))
      opPtr.p = &opBusy;
    opPtr.p->save(req);
    opPtr.p->m_coordinatorRef = senderRef;
    opPtr.p->m_isMaster = (senderRef == reference());
    opPtr.p->key = opKey;
    opPtr.p->m_requestType = DropTrigReq::RT_DICT_PREPARE;
    if (opPtr.p == &opBusy) {
      jam();
      opPtr.p->m_errorCode = DropTrigRef::Busy;
      opPtr.p->m_errorLine = __LINE__;
      dropTrigger_sendReply(signal, opPtr, opPtr.p->m_isMaster);
      return;
    }
    c_opDropTrigger.add(opPtr);
      // master expects to hear from all
    if (opPtr.p->m_isMaster)
	opPtr.p->m_signalCounter = c_aliveNodes;
    dropTrigger_slavePrepare(signal, opPtr);
    dropTrigger_sendReply(signal, opPtr, false);
    return;
  }
  c_opDropTrigger.find(opPtr, req->getConnectionPtr());
  if (! opPtr.isNull()) {
    opPtr.p->m_requestType = requestType;
    if (requestType == DropTrigReq::RT_DICT_COMMIT ||
	requestType == DropTrigReq::RT_DICT_ABORT) {
      jam();
      if (requestType == DropTrigReq::RT_DICT_COMMIT)
	dropTrigger_slaveCommit(signal, opPtr);
      else
	dropTrigger_slaveAbort(signal, opPtr);
      dropTrigger_sendReply(signal, opPtr, false);
      // done in slave
      if (! opPtr.p->m_isMaster)
	c_opDropTrigger.release(opPtr);
      return;
    }
  }
  jam();
  // return to sender
  OpDropTrigger opBad;
  opPtr.p = &opBad;
  opPtr.p->save(req);
  opPtr.p->m_errorCode = DropTrigRef::BadRequestType;
  opPtr.p->m_errorLine = __LINE__;
  dropTrigger_sendReply(signal,  opPtr, true);
}

void
Dbdict::execDROP_TRIG_CONF(Signal* signal) 
{
  jamEntry();
  DropTrigConf* conf = (DropTrigConf*)signal->getDataPtrSend();
  dropTrigger_recvReply(signal, conf, 0);
}

void
Dbdict::execDROP_TRIG_REF(Signal* signal) 
{
  jamEntry();
  DropTrigRef* ref = (DropTrigRef*)signal->getDataPtrSend();
  dropTrigger_recvReply(signal, ref->getConf(), ref);
}

void
Dbdict::dropTrigger_recvReply(Signal* signal, const DropTrigConf* conf,
    const DropTrigRef* ref)
{
  jam();
  const Uint32 senderRef = signal->senderBlockRef();
  const DropTrigReq::RequestType requestType = conf->getRequestType();
  const Uint32 key = conf->getConnectionPtr();
  if (requestType == DropTrigReq::RT_ALTER_INDEX) {
    jam();
    // part of alter index operation
    OpAlterIndexPtr opPtr;
    c_opAlterIndex.find(opPtr, key);
    ndbrequire(! opPtr.isNull());
    opPtr.p->setError(ref);
    alterIndex_fromDropTrigger(signal, opPtr);
    return;
  }
  if (requestType == DropTrigReq::RT_BUILD_INDEX) {
    jam();
    // part of build index operation
    OpBuildIndexPtr opPtr;
    c_opBuildIndex.find(opPtr, key);
    ndbrequire(! opPtr.isNull());
    opPtr.p->setError(ref);
    buildIndex_fromDropConstr(signal, opPtr);
    return;
  }
  if (requestType == DropTrigReq::RT_TC ||
      requestType == DropTrigReq::RT_LQH) {
    jam();
    // part of alter trigger operation
    OpAlterTriggerPtr opPtr;
    c_opAlterTrigger.find(opPtr, key);
    ndbrequire(! opPtr.isNull());
    opPtr.p->setError(ref);
    alterTrigger_fromDropLocal(signal, opPtr);
    return;
  }
  OpDropTriggerPtr opPtr;
  c_opDropTrigger.find(opPtr, key);
  ndbrequire(! opPtr.isNull());
  ndbrequire(opPtr.p->m_isMaster);
  ndbrequire(opPtr.p->m_requestType == requestType);
  opPtr.p->setError(ref);
  opPtr.p->m_signalCounter.clearWaitingFor(refToNode(senderRef));
  if (! opPtr.p->m_signalCounter.done()) {
    jam();
    return;
  }
  if (requestType == DropTrigReq::RT_DICT_COMMIT ||
      requestType == DropTrigReq::RT_DICT_ABORT) {
    jam();
    // send reply to user
    dropTrigger_sendReply(signal, opPtr, true);
    c_opDropTrigger.release(opPtr);
    return;
  }
  if (opPtr.p->hasError()) {
    jam();
    opPtr.p->m_requestType = DropTrigReq::RT_DICT_ABORT;
    dropTrigger_sendSlaveReq(signal, opPtr);
    return;
  }
  if (requestType == DropTrigReq::RT_DICT_PREPARE) {
    jam();
    // start alter offline
    dropTrigger_toAlterTrigger(signal, opPtr);
    return;
  }
  ndbrequire(false);
}

void
Dbdict::dropTrigger_slavePrepare(Signal* signal, OpDropTriggerPtr opPtr)
{
  jam();
}

void
Dbdict::dropTrigger_toAlterTrigger(Signal* signal, OpDropTriggerPtr opPtr)
{
  jam();
  AlterTrigReq* req = (AlterTrigReq*)signal->getDataPtrSend();
  req->setUserRef(reference());
  req->setConnectionPtr(opPtr.p->key);
  req->setRequestType(AlterTrigReq::RT_DROP_TRIGGER);
  req->setTableId(opPtr.p->m_request.getTableId());
  req->setTriggerId(opPtr.p->m_request.getTriggerId());
  req->setTriggerInfo(0);       // not used
  req->setOnline(false);
  req->setReceiverRef(0);
  sendSignal(reference(), GSN_ALTER_TRIG_REQ,
      signal, AlterTrigReq::SignalLength, JBB);
}

void
Dbdict::dropTrigger_fromAlterTrigger(Signal* signal, OpDropTriggerPtr opPtr)
{
  jam();
  // remove in all
  opPtr.p->m_requestType = DropTrigReq::RT_DICT_COMMIT;
  dropTrigger_sendSlaveReq(signal, opPtr);
}

void
Dbdict::dropTrigger_sendSlaveReq(Signal* signal, OpDropTriggerPtr opPtr)
{
  DropTrigReq* const req = (DropTrigReq*)signal->getDataPtrSend();
  *req = opPtr.p->m_request;
  req->setUserRef(opPtr.p->m_coordinatorRef);
  req->setConnectionPtr(opPtr.p->key);
  req->setRequestType(opPtr.p->m_requestType);
  req->addRequestFlag(opPtr.p->m_requestFlag);
  opPtr.p->m_signalCounter = c_aliveNodes;
  NodeReceiverGroup rg(DBDICT, c_aliveNodes);
  sendSignal(rg, GSN_DROP_TRIG_REQ,
      signal, DropTrigReq::SignalLength, JBB);
}

void
Dbdict::dropTrigger_slaveCommit(Signal* signal, OpDropTriggerPtr opPtr)
{
  jam();
  const DropTrigReq* const req = &opPtr.p->m_request;
  // get trigger record
  const Uint32 triggerId = req->getTriggerId();
  TriggerRecordPtr triggerPtr;
  c_triggerRecordPool.getPtr(triggerPtr, triggerId);
  if (triggerPtr.p->triggerType == TriggerType::SECONDARY_INDEX ||
      triggerPtr.p->triggerType == TriggerType::ORDERED_INDEX) {
    jam();
    // disconnect from index if index trigger  XXX move to drop index
    triggerPtr.p->indexId = req->getIndexId();
    TableRecordPtr indexPtr;
    c_tableRecordPool.getPtr(indexPtr, triggerPtr.p->indexId);
    ndbrequire(! indexPtr.isNull());
    switch (triggerPtr.p->triggerEvent) {
    case TriggerEvent::TE_INSERT:
      indexPtr.p->insertTriggerId = RNIL;
      break;
    case TriggerEvent::TE_UPDATE:
      indexPtr.p->updateTriggerId = RNIL;
      break;
    case TriggerEvent::TE_DELETE:
      indexPtr.p->deleteTriggerId = RNIL;
      break;
    case TriggerEvent::TE_CUSTOM:
      indexPtr.p->customTriggerId = RNIL;
      break;
    default:
      ndbrequire(false);
      break;
    }
  }
  if (triggerPtr.p->triggerType == TriggerType::READ_ONLY_CONSTRAINT) {
    jam();
    // disconnect from index record  XXX should be done in caller instead
    triggerPtr.p->indexId = req->getTableId();
    TableRecordPtr indexPtr;
    c_tableRecordPool.getPtr(indexPtr, triggerPtr.p->indexId);
    indexPtr.p->buildTriggerId = RNIL;
  }
  // remove trigger
  //  ndbout_c("++++++++++++ Removing trigger id %u, %s", triggerPtr.p->triggerId, triggerPtr.p->triggerName);
  c_triggerRecordHash.remove(triggerPtr);
  triggerPtr.p->triggerState = TriggerRecord::TS_NOT_DEFINED;
}

void
Dbdict::dropTrigger_slaveAbort(Signal* signal, OpDropTriggerPtr opPtr)
{
  jam();
}

void
Dbdict::dropTrigger_sendReply(Signal* signal, OpDropTriggerPtr opPtr,
    bool toUser)
{
  DropTrigRef* rep = (DropTrigRef*)signal->getDataPtrSend();
  Uint32 gsn = GSN_DROP_TRIG_CONF;
  Uint32 length = DropTrigConf::InternalLength;
  bool sendRef = opPtr.p->hasError();
  if (! toUser) {
    rep->setUserRef(opPtr.p->m_coordinatorRef);
    rep->setConnectionPtr(opPtr.p->key);
    rep->setRequestType(opPtr.p->m_requestType);
    if (opPtr.p->m_requestType == DropTrigReq::RT_DICT_ABORT)
      sendRef = false;
  } else {
    rep->setUserRef(opPtr.p->m_request.getUserRef());
    rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr());
    rep->setRequestType(opPtr.p->m_request.getRequestType());
    length = DropTrigConf::SignalLength;
  }
  rep->setTableId(opPtr.p->m_request.getTableId());
  rep->setIndexId(opPtr.p->m_request.getIndexId());
  rep->setTriggerId(opPtr.p->m_request.getTriggerId());
  if (sendRef) {
    if (opPtr.p->m_errorNode == 0)
      opPtr.p->m_errorNode = getOwnNodeId();
    rep->setErrorCode(opPtr.p->m_errorCode);
    rep->setErrorLine(opPtr.p->m_errorLine);
    rep->setErrorNode(opPtr.p->m_errorNode);
    gsn = GSN_DROP_TRIG_REF;
    length = CreateTrigRef::SignalLength;
  }
  sendSignal(rep->getUserRef(), gsn, signal, length, JBB);
}

/**
 * MODULE: Alter trigger.
 *
 * Alter trigger state.  Alter online creates the trigger first in all
 * TC (if index trigger) and then in all LQH-TUP.
 *
 * Request type received in REQ and returned in CONF/REF:
 *
 * RT_USER - normal user e.g. BACKUP
 * RT_CREATE_TRIGGER - from create trigger
 * RT_DROP_TRIGGER - from drop trigger
 * RT_DICT_PREPARE - seize operations and check request
 * RT_DICT_TC - master to each DICT on way to TC
 * RT_DICT_LQH - master to each DICT on way to LQH-TUP
 * RT_DICT_COMMIT - commit state change in each DICT (no reply)
 */

void
Dbdict::execALTER_TRIG_REQ(Signal* signal) 
{
  jamEntry();
  AlterTrigReq* const req = (AlterTrigReq*)signal->getDataPtrSend();
  OpAlterTriggerPtr opPtr;
  const Uint32 senderRef = signal->senderBlockRef();
  const AlterTrigReq::RequestType requestType = req->getRequestType();
  if (requestType == AlterTrigReq::RT_USER ||
      requestType == AlterTrigReq::RT_CREATE_TRIGGER ||
      requestType == AlterTrigReq::RT_DROP_TRIGGER) {
    jam();
    const bool isLocal = req->getRequestFlag() & RequestFlag::RF_LOCAL;
    NdbNodeBitmask receiverNodes = c_aliveNodes;
    if (isLocal) {
      receiverNodes.clear();
      receiverNodes.set(getOwnNodeId());
    }
    if (signal->getLength() == AlterTrigReq::SignalLength) {
      jam();
      if (! isLocal && getOwnNodeId() != c_masterNodeId) {
        jam();
        // forward to DICT master
        sendSignal(calcDictBlockRef(c_masterNodeId), GSN_ALTER_TRIG_REQ,
            signal, AlterTrigReq::SignalLength, JBB);
        return;
      }
      // forward initial request plus operation key to all
      req->setOpKey(++c_opRecordSequence);
      NodeReceiverGroup rg(DBDICT, receiverNodes);
      sendSignal(rg, GSN_ALTER_TRIG_REQ,
          signal, AlterTrigReq::SignalLength + 1, JBB);
      return;
    }
    // seize operation record
    ndbrequire(signal->getLength() == AlterTrigReq::SignalLength + 1);
    const Uint32 opKey = req->getOpKey();
    OpAlterTrigger opBusy;
    if (! c_opAlterTrigger.seize(opPtr))
      opPtr.p = &opBusy;
    opPtr.p->save(req);
    opPtr.p->m_coordinatorRef = senderRef;
    opPtr.p->m_isMaster = (senderRef == reference());
    opPtr.p->key = opKey;
    opPtr.p->m_requestType = AlterTrigReq::RT_DICT_PREPARE;
    if (opPtr.p == &opBusy) {
      jam();
      opPtr.p->m_errorCode = AlterTrigRef::Busy;
      opPtr.p->m_errorLine = __LINE__;
      alterTrigger_sendReply(signal, opPtr, opPtr.p->m_isMaster);
      return;
    }
    c_opAlterTrigger.add(opPtr);
    // master expects to hear from all
    if (opPtr.p->m_isMaster) {
      opPtr.p->m_nodes = receiverNodes;
      opPtr.p->m_signalCounter = receiverNodes;
    }
    alterTrigger_slavePrepare(signal, opPtr);
    alterTrigger_sendReply(signal, opPtr, false);
    return;
  }
  c_opAlterTrigger.find(opPtr, req->getConnectionPtr());
  if (! opPtr.isNull()) {
    opPtr.p->m_requestType = requestType;
    if (requestType == AlterTrigReq::RT_DICT_TC ||
        requestType == AlterTrigReq::RT_DICT_LQH) {
      jam();
      if (req->getOnline())
        alterTrigger_toCreateLocal(signal, opPtr);
      else
        alterTrigger_toDropLocal(signal, opPtr);
      return;
    }
    if (requestType == AlterTrigReq::RT_DICT_COMMIT ||
        requestType == AlterTrigReq::RT_DICT_ABORT) {
      jam();
      if (requestType == AlterTrigReq::RT_DICT_COMMIT)
        alterTrigger_slaveCommit(signal, opPtr);
      else
        alterTrigger_slaveAbort(signal, opPtr);
      alterTrigger_sendReply(signal, opPtr, false);
      // done in slave
      if (! opPtr.p->m_isMaster)
        c_opAlterTrigger.release(opPtr);
      return;
    }
  }
  jam();
  // return to sender
  OpAlterTrigger opBad;
  opPtr.p = &opBad;
  opPtr.p->save(req);
  opPtr.p->m_errorCode = AlterTrigRef::BadRequestType;
  opPtr.p->m_errorLine = __LINE__;
  alterTrigger_sendReply(signal, opPtr, true);
  return;
}

void
Dbdict::execALTER_TRIG_CONF(Signal* signal) 
{
  jamEntry();
  AlterTrigConf* conf = (AlterTrigConf*)signal->getDataPtrSend();
  alterTrigger_recvReply(signal, conf, 0);
}

void
Dbdict::execALTER_TRIG_REF(Signal* signal) 
{
  jamEntry();
  AlterTrigRef* ref = (AlterTrigRef*)signal->getDataPtrSend();
  alterTrigger_recvReply(signal, ref->getConf(), ref);
}

void
Dbdict::alterTrigger_recvReply(Signal* signal, const AlterTrigConf* conf,
    const AlterTrigRef* ref)
{
  jam();
  const Uint32 senderRef = signal->senderBlockRef();
  const AlterTrigReq::RequestType requestType = conf->getRequestType();
  const Uint32 key = conf->getConnectionPtr();
  if (requestType == AlterTrigReq::RT_CREATE_TRIGGER) {
    jam();
    // part of create trigger operation
    OpCreateTriggerPtr opPtr;
    c_opCreateTrigger.find(opPtr, key);
    ndbrequire(! opPtr.isNull());
    opPtr.p->setError(ref);
    createTrigger_fromAlterTrigger(signal, opPtr);
    return;
  }
  if (requestType == AlterTrigReq::RT_DROP_TRIGGER) {
    jam();
    // part of drop trigger operation
    OpDropTriggerPtr opPtr;
    c_opDropTrigger.find(opPtr, key);
    ndbrequire(! opPtr.isNull());
    opPtr.p->setError(ref);
    dropTrigger_fromAlterTrigger(signal, opPtr);
    return;
  }
  OpAlterTriggerPtr opPtr;
  c_opAlterTrigger.find(opPtr, key);
  ndbrequire(! opPtr.isNull());
  ndbrequire(opPtr.p->m_isMaster);
  ndbrequire(opPtr.p->m_requestType == requestType);
  /* 
   * If refuse on drop trig, because of non-existent trigger,
   * comes from anyone but the master node - ignore it and
   * remove the node from forter ALTER_TRIG communication
   * This will happen if a new node has started since the
   * trigger whas created.
   */
  if (ref &&
      refToNode(senderRef) != refToNode(reference()) &&
      opPtr.p->m_request.getRequestType() == AlterTrigReq::RT_DROP_TRIGGER &&
      ref->getErrorCode() == AlterTrigRef::TriggerNotFound) {
    jam();
    ref = 0;                                      // ignore this error
    opPtr.p->m_nodes.clear(refToNode(senderRef)); // remove this from group
  }
  opPtr.p->setError(ref);
  opPtr.p->m_signalCounter.clearWaitingFor(refToNode(senderRef));
  if (! opPtr.p->m_signalCounter.done()) {
    jam();
    return;
  }
  if (requestType == AlterTrigReq::RT_DICT_COMMIT ||
      requestType == AlterTrigReq::RT_DICT_ABORT) {
    jam();
    // send reply to user
    alterTrigger_sendReply(signal, opPtr, true);
    c_opAlterTrigger.release(opPtr);
    return;
  }
  if (opPtr.p->hasError()) {
    jam();
    opPtr.p->m_requestType = AlterTrigReq::RT_DICT_ABORT;
    alterTrigger_sendSlaveReq(signal, opPtr);
    return;
  }
  if (! (opPtr.p->m_request.getRequestFlag() & RequestFlag::RF_NOTCTRIGGER)) {
    if (requestType == AlterTrigReq::RT_DICT_PREPARE) {
      jam();
      if (opPtr.p->m_request.getOnline())
        opPtr.p->m_requestType = AlterTrigReq::RT_DICT_TC;
      else
        opPtr.p->m_requestType = AlterTrigReq::RT_DICT_LQH;
      alterTrigger_sendSlaveReq(signal, opPtr);
      return;
    }
    if (requestType == AlterTrigReq::RT_DICT_TC) {
      jam();
      if (opPtr.p->m_request.getOnline())
        opPtr.p->m_requestType = AlterTrigReq::RT_DICT_LQH;
      else
        opPtr.p->m_requestType = AlterTrigReq::RT_DICT_COMMIT;
      alterTrigger_sendSlaveReq(signal, opPtr);
      return;
    }
    if (requestType == AlterTrigReq::RT_DICT_LQH) {
      jam();
      if (opPtr.p->m_request.getOnline())
        opPtr.p->m_requestType = AlterTrigReq::RT_DICT_COMMIT;
      else
        opPtr.p->m_requestType = AlterTrigReq::RT_DICT_TC;
      alterTrigger_sendSlaveReq(signal, opPtr);
      return;
    }
  } else {
    if (requestType == AlterTrigReq::RT_DICT_PREPARE) {
      jam();
      opPtr.p->m_requestType = AlterTrigReq::RT_DICT_LQH;
      alterTrigger_sendSlaveReq(signal, opPtr);
      return;
    }
    if (requestType == AlterTrigReq::RT_DICT_LQH) {
      jam();
      opPtr.p->m_requestType = AlterTrigReq::RT_DICT_COMMIT;
      alterTrigger_sendSlaveReq(signal, opPtr);
      return;
    }
  }
  ndbrequire(false);
}

void
Dbdict::alterTrigger_slavePrepare(Signal* signal, OpAlterTriggerPtr opPtr)
{
  jam();
  const AlterTrigReq* const req = &opPtr.p->m_request;
  const Uint32 triggerId = req->getTriggerId();
  TriggerRecordPtr triggerPtr;
  if (! (triggerId < c_triggerRecordPool.getSize())) {
    jam();
    opPtr.p->m_errorCode = AlterTrigRef::TriggerNotFound;
    opPtr.p->m_errorLine = __LINE__;
    return;
  }
  c_triggerRecordPool.getPtr(triggerPtr, triggerId);
  if (triggerPtr.p->triggerState == TriggerRecord::TS_NOT_DEFINED) {
    jam();
    opPtr.p->m_errorCode = AlterTrigRef::TriggerNotFound;
    opPtr.p->m_errorLine = __LINE__;
    return;
  }
}

void
Dbdict::alterTrigger_toCreateLocal(Signal* signal, OpAlterTriggerPtr opPtr)
{
  jam();
  // find trigger record
  const Uint32 triggerId = opPtr.p->m_request.getTriggerId();
  TriggerRecordPtr triggerPtr;
  c_triggerRecordPool.getPtr(triggerPtr, triggerId);
  CreateTrigReq* const req = (CreateTrigReq*)signal->getDataPtrSend();
  req->setUserRef(reference());
  req->setConnectionPtr(opPtr.p->key);
  if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_TC) {
    req->setRequestType(CreateTrigReq::RT_TC);
  } else if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_LQH) {
    req->setRequestType(CreateTrigReq::RT_LQH);
  } else {
    ndbassert(false);
  }
  req->setTableId(triggerPtr.p->tableId);
  req->setIndexId(triggerPtr.p->indexId);
  req->setTriggerId(triggerPtr.i);
  req->setTriggerType(triggerPtr.p->triggerType);
  req->setTriggerActionTime(triggerPtr.p->triggerActionTime);
  req->setTriggerEvent(triggerPtr.p->triggerEvent);
  req->setMonitorReplicas(triggerPtr.p->monitorReplicas);
  req->setMonitorAllAttributes(triggerPtr.p->monitorAllAttributes);
  req->setOnline(true);
  req->setReceiverRef(opPtr.p->m_request.getReceiverRef());
  BlockReference blockRef = 0;
  if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_TC) {
    blockRef = calcTcBlockRef(getOwnNodeId());
  } else if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_LQH) {
    blockRef = calcLqhBlockRef(getOwnNodeId());
  } else {
    ndbassert(false);
  }
  req->setAttributeMask(triggerPtr.p->attributeMask);
  sendSignal(blockRef, GSN_CREATE_TRIG_REQ,
      signal, CreateTrigReq::SignalLength, JBB);
}

void
Dbdict::alterTrigger_fromCreateLocal(Signal* signal, OpAlterTriggerPtr opPtr)
{
  jam();
  if (! opPtr.p->hasError()) {
    // mark created locally
    TriggerRecordPtr triggerPtr;
    c_triggerRecordPool.getPtr(triggerPtr, opPtr.p->m_request.getTriggerId());
    if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_TC) {
      triggerPtr.p->triggerLocal |= TriggerRecord::TL_CREATED_TC;
    } else if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_LQH) {
      triggerPtr.p->triggerLocal |= TriggerRecord::TL_CREATED_LQH;
    } else {
      ndbrequire(false);
    }
  }
  // forward CONF or REF to master
  alterTrigger_sendReply(signal, opPtr, false);
}

void
Dbdict::alterTrigger_toDropLocal(Signal* signal, OpAlterTriggerPtr opPtr)
{
  jam();
  TriggerRecordPtr triggerPtr;
  c_triggerRecordPool.getPtr(triggerPtr, opPtr.p->m_request.getTriggerId());
  DropTrigReq* const req = (DropTrigReq*)signal->getDataPtrSend();
  req->setUserRef(reference());
  req->setConnectionPtr(opPtr.p->key);
  if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_TC) {
    // broken trigger
    if (! (triggerPtr.p->triggerLocal & TriggerRecord::TL_CREATED_TC)) {
      jam();
      alterTrigger_sendReply(signal, opPtr, false);
      return;
    }
    req->setRequestType(DropTrigReq::RT_TC);
  } else if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_LQH) {
    // broken trigger
    if (! (triggerPtr.p->triggerLocal & TriggerRecord::TL_CREATED_LQH)) {
      jam();
      alterTrigger_sendReply(signal, opPtr, false);
      return;
    }
    req->setRequestType(DropTrigReq::RT_LQH);
  } else {
    ndbassert(false);
  }
  req->setTableId(triggerPtr.p->tableId);
  req->setIndexId(triggerPtr.p->indexId);
  req->setTriggerId(triggerPtr.i);
  req->setTriggerType(triggerPtr.p->triggerType);
  req->setTriggerActionTime(triggerPtr.p->triggerActionTime);
  req->setTriggerEvent(triggerPtr.p->triggerEvent);
  req->setMonitorReplicas(triggerPtr.p->monitorReplicas);
  req->setMonitorAllAttributes(triggerPtr.p->monitorAllAttributes);
  BlockReference blockRef = 0;
  if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_TC) {
    blockRef = calcTcBlockRef(getOwnNodeId());
  } else if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_LQH) {
    blockRef = calcLqhBlockRef(getOwnNodeId());
  } else {
    ndbassert(false);
  }
  sendSignal(blockRef, GSN_DROP_TRIG_REQ,
      signal, DropTrigReq::SignalLength, JBB);
}

void
Dbdict::alterTrigger_fromDropLocal(Signal* signal, OpAlterTriggerPtr opPtr)
{
  jam();
  if (! opPtr.p->hasError()) {
    // mark dropped locally
    TriggerRecordPtr triggerPtr;
    c_triggerRecordPool.getPtr(triggerPtr, opPtr.p->m_request.getTriggerId());
    if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_TC) {
      triggerPtr.p->triggerLocal &= ~TriggerRecord::TL_CREATED_TC;
    } else if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_LQH) {
      triggerPtr.p->triggerLocal &= ~TriggerRecord::TL_CREATED_LQH;
    } else {
      ndbrequire(false);
    }
  }
  // forward CONF or REF to master
  alterTrigger_sendReply(signal, opPtr, false);
}

void
Dbdict::alterTrigger_slaveCommit(Signal* signal, OpAlterTriggerPtr opPtr)
{
  jam();
  TriggerRecordPtr triggerPtr;
  c_triggerRecordPool.getPtr(triggerPtr, opPtr.p->m_request.getTriggerId());
  // set state
  triggerPtr.p->triggerState = TriggerRecord::TS_ONLINE;
}

void
Dbdict::alterTrigger_slaveAbort(Signal* signal, OpAlterTriggerPtr opPtr)
{
  jam();
}

void
Dbdict::alterTrigger_sendSlaveReq(Signal* signal, OpAlterTriggerPtr opPtr)
{
  AlterTrigReq* const req = (AlterTrigReq*)signal->getDataPtrSend();
  *req = opPtr.p->m_request;
  req->setUserRef(opPtr.p->m_coordinatorRef);
  req->setConnectionPtr(opPtr.p->key);
  req->setRequestType(opPtr.p->m_requestType);
  req->addRequestFlag(opPtr.p->m_requestFlag);
  NdbNodeBitmask receiverNodes = c_aliveNodes;
  if (opPtr.p->m_requestFlag & RequestFlag::RF_LOCAL) {
    receiverNodes.clear();
    receiverNodes.set(getOwnNodeId());
  } else {
    opPtr.p->m_nodes.bitAND(receiverNodes);
    receiverNodes = opPtr.p->m_nodes;
  }
  opPtr.p->m_signalCounter = receiverNodes;
  NodeReceiverGroup rg(DBDICT, receiverNodes);
  sendSignal(rg, GSN_ALTER_TRIG_REQ,
      signal, AlterTrigReq::SignalLength, JBB);
}

void
Dbdict::alterTrigger_sendReply(Signal* signal, OpAlterTriggerPtr opPtr,
    bool toUser)
{
  jam();
  AlterTrigRef* rep = (AlterTrigRef*)signal->getDataPtrSend();
  Uint32 gsn = GSN_ALTER_TRIG_CONF;
  Uint32 length = AlterTrigConf::InternalLength;
  bool sendRef = opPtr.p->hasError();
  if (! toUser) {
    rep->setUserRef(opPtr.p->m_coordinatorRef);
    rep->setConnectionPtr(opPtr.p->key);
    rep->setRequestType(opPtr.p->m_requestType);
    if (opPtr.p->m_requestType == AlterTrigReq::RT_DICT_ABORT) {
      jam();
      sendRef = false;
    } else {
      jam();
    }
  } else {
    jam();
    rep->setUserRef(opPtr.p->m_request.getUserRef());
    rep->setConnectionPtr(opPtr.p->m_request.getConnectionPtr());
    rep->setRequestType(opPtr.p->m_request.getRequestType());
    length = AlterTrigConf::SignalLength;
  }
  rep->setTableId(opPtr.p->m_request.getTableId());
  rep->setTriggerId(opPtr.p->m_request.getTriggerId());
  if (sendRef) {
    if (opPtr.p->m_errorNode == 0) {
      jam();
      opPtr.p->m_errorNode = getOwnNodeId();
    } else {
      jam();
    }
    rep->setErrorCode(opPtr.p->m_errorCode);
    rep->setErrorLine(opPtr.p->m_errorLine);
    rep->setErrorNode(opPtr.p->m_errorNode);
    gsn = GSN_ALTER_TRIG_REF;
    length = AlterTrigRef::SignalLength;
  }
  sendSignal(rep->getUserRef(), gsn, signal, length, JBB);
}

/**
 * MODULE: Support routines for index and trigger.
 */

void
Dbdict::getTableKeyList(TableRecordPtr tablePtr, AttributeList& list)
{
  jam();
  list.sz = 0;
  for (Uint32 tAttr = tablePtr.p->firstAttribute; tAttr != RNIL; ) {
    AttributeRecord* aRec = c_attributeRecordPool.getPtr(tAttr);
    if (aRec->tupleKey)
      list.id[list.sz++] = aRec->attributeId;
    tAttr = aRec->nextAttrInTable;
  }
}

// XXX should store the primary attribute id
void
Dbdict::getIndexAttr(TableRecordPtr indexPtr, Uint32 itAttr, Uint32* id)
{
  jam();
  TableRecordPtr tablePtr;
  c_tableRecordPool.getPtr(tablePtr, indexPtr.p->primaryTableId);
  AttributeRecord* iaRec = c_attributeRecordPool.getPtr(itAttr);
  for (Uint32 tAttr = tablePtr.p->firstAttribute; tAttr != RNIL; ) {
    AttributeRecord* aRec = c_attributeRecordPool.getPtr(tAttr);
    if (iaRec->equal(*aRec)) {
      id[0] = aRec->attributeId;
      return;
    }
    tAttr = aRec->nextAttrInTable;
  }
  ndbrequire(false);
}

void
Dbdict::getIndexAttrList(TableRecordPtr indexPtr, AttributeList& list)
{
  jam();
  TableRecordPtr tablePtr;
  c_tableRecordPool.getPtr(tablePtr, indexPtr.p->primaryTableId);
  list.sz = 0;
  memset(list.id, 0, sizeof(list.id));
  ndbrequire(indexPtr.p->noOfAttributes >= 2);
  Uint32 itAttr = indexPtr.p->firstAttribute;
  for (Uint32 i = 0; i < (Uint32)indexPtr.p->noOfAttributes - 1; i++) {
    getIndexAttr(indexPtr, itAttr, &list.id[list.sz++]);
    AttributeRecord* iaRec = c_attributeRecordPool.getPtr(itAttr);
    itAttr = iaRec->nextAttrInTable;
  }
}

void
Dbdict::getIndexAttrMask(TableRecordPtr indexPtr, AttributeMask& mask)
{
  jam();
  TableRecordPtr tablePtr;
  c_tableRecordPool.getPtr(tablePtr, indexPtr.p->primaryTableId);
  mask.clear();
  ndbrequire(indexPtr.p->noOfAttributes >= 2);
  Uint32 itAttr = indexPtr.p->firstAttribute;
  for (Uint32 i = 0; i < (Uint32)indexPtr.p->noOfAttributes - 1; i++) {
    Uint32 id;
    getIndexAttr(indexPtr, itAttr, &id);
    mask.set(id);
    AttributeRecord* iaRec = c_attributeRecordPool.getPtr(itAttr);
    itAttr = iaRec->nextAttrInTable;
  }
}

/* **************************************************************** */
/* ---------------------------------------------------------------- */
/* MODULE:          STORE/RESTORE SCHEMA FILE---------------------- */
/* ---------------------------------------------------------------- */
/*                                                                  */
/* General module used to store the schema file on disk and         */
/* similar function to restore it from disk.                        */
/* ---------------------------------------------------------------- */
/* **************************************************************** */

void
Dbdict::initSchemaFile(SchemaFile * sf, Uint32 fileSz){
  memcpy(sf->Magic, "NDBSCHMA", sizeof(sf->Magic));
  sf->ByteOrder = 0x12345678;
  sf->NdbVersion =  NDB_VERSION;
  sf->FileSize = fileSz;
  sf->CheckSum = 0;
  
  Uint32 headSz = (sizeof(SchemaFile)-sizeof(SchemaFile::TableEntry));
  Uint32 noEntries = (fileSz - headSz) / sizeof(SchemaFile::TableEntry);
  Uint32 slack = (fileSz - headSz) - noEntries * sizeof(SchemaFile::TableEntry);
  
  ndbrequire(noEntries > MAX_TABLES);

  sf->NoOfTableEntries = noEntries;
  memset(sf->TableEntries, 0, noEntries*sizeof(SchemaFile::TableEntry));
  memset(&(sf->TableEntries[noEntries]), 0, slack);
  computeChecksum(sf);
}

void
Dbdict::computeChecksum(SchemaFile * sf){ 
  sf->CheckSum = 0;
  sf->CheckSum = computeChecksum((const Uint32*)sf, sf->FileSize/4);
}

bool 
Dbdict::validateChecksum(const SchemaFile * sf){
  
  Uint32 c = computeChecksum((const Uint32*)sf, sf->FileSize/4);
  return c == 0;
}

Uint32
Dbdict::computeChecksum(const Uint32 * src, Uint32 len){
  Uint32 ret = 0;
  for(Uint32 i = 0; i<len; i++)
    ret ^= src[i];
  return ret;
}

SchemaFile::TableEntry * 
Dbdict::getTableEntry(void * p, Uint32 tableId, bool allowTooBig){
  SchemaFile * sf = (SchemaFile*)p;
  
  ndbrequire(allowTooBig || tableId < sf->NoOfTableEntries);
  return &sf->TableEntries[tableId];
}

// global metadata support

int
Dbdict::getMetaTablePtr(TableRecordPtr& tablePtr, Uint32 tableId, Uint32 tableVersion)
{
  if (tableId >= c_tableRecordPool.getSize()) {
    return MetaData::InvalidArgument;
  }
  c_tableRecordPool.getPtr(tablePtr, tableId);
  if (tablePtr.p->tabState == TableRecord::NOT_DEFINED) {
    return MetaData::TableNotFound;
  }
  if (tablePtr.p->tableVersion != tableVersion) {
    return MetaData::InvalidTableVersion;
  }
  // online flag is not maintained by DICT
  tablePtr.p->online =
    tablePtr.p->isTable() && tablePtr.p->tabState == TableRecord::DEFINED ||
    tablePtr.p->isIndex() && tablePtr.p->indexState == TableRecord::IS_ONLINE;
  return 0;
}

int
Dbdict::getMetaTable(MetaData::Table& table, Uint32 tableId, Uint32 tableVersion)
{
  int ret;
  TableRecordPtr tablePtr;
  if ((ret = getMetaTablePtr(tablePtr, tableId, tableVersion)) < 0) {
    return ret;
  }
  new (&table) MetaData::Table(*tablePtr.p);
  return 0;
}

int
Dbdict::getMetaTable(MetaData::Table& table, const char* tableName)
{
  int ret;
  TableRecordPtr tablePtr;
  if (strlen(tableName) + 1 > MAX_TAB_NAME_SIZE) {
    return MetaData::InvalidArgument;
  }
  TableRecord keyRecord;
  strcpy(keyRecord.tableName, tableName);
  c_tableRecordHash.find(tablePtr, keyRecord);
  if (tablePtr.i == RNIL) {
    return MetaData::TableNotFound;
  }
  if ((ret = getMetaTablePtr(tablePtr, tablePtr.i, tablePtr.p->tableVersion)) < 0) {
    return ret;
  }
  new (&table) MetaData::Table(*tablePtr.p);
  return 0;
}

int
Dbdict::getMetaAttribute(MetaData::Attribute& attr, const MetaData::Table& table, Uint32 attributeId)
{
  int ret;
  TableRecordPtr tablePtr;
  if ((ret = getMetaTablePtr(tablePtr, table.tableId, table.tableVersion)) < 0) {
    return ret;
  }
  AttributeRecordPtr attrPtr;
  attrPtr.i = tablePtr.p->firstAttribute;
  while (attrPtr.i != RNIL) {
    c_attributeRecordPool.getPtr(attrPtr);
    if (attrPtr.p->attributeId == attributeId)
      break;
    attrPtr.i = attrPtr.p->nextAttrInTable;
  }
  if (attrPtr.i == RNIL) {
    return MetaData::AttributeNotFound;
  }
  new (&attr) MetaData::Attribute(*attrPtr.p);
  return 0;
}

int
Dbdict::getMetaAttribute(MetaData::Attribute& attr, const MetaData::Table& table, const char* attributeName)
{
  int ret;
  TableRecordPtr tablePtr;
  if ((ret = getMetaTablePtr(tablePtr, table.tableId, table.tableVersion)) < 0) {
    return ret;
  }
  AttributeRecordPtr attrPtr;
  attrPtr.i = tablePtr.p->firstAttribute;
  while (attrPtr.i != RNIL) {
    c_attributeRecordPool.getPtr(attrPtr);
    if (strcmp(attrPtr.p->attributeName, attributeName) == 0)
      break;
    attrPtr.i = attrPtr.p->nextAttrInTable;
  }
  if (attrPtr.i == RNIL) {
    return MetaData::AttributeNotFound;
  }
  new (&attr) MetaData::Attribute(*attrPtr.p);
  return 0;
}
