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

ChangeSet@stripped, 2007-03-28 12:17:09+02:00, knielsen@ymer.(none) +7 -0
  Merge ymer.(none):/usr/local/mysql/mysql-5.0-ndb-bug27370
  into  ymer.(none):/usr/local/mysql/mysql-5.1-new-ndb-bug27370
  MERGE: 1.1810.2731.1

  storage/ndb/include/kernel/signaldata/ScanTab.hpp@stripped, 2007-03-28 12:17:06+02:00,
knielsen@ymer.(none) +6 -5
    Manual merge.
    MERGE: 1.13.2.2

  storage/ndb/include/kernel/signaldata/ScanTab.hpp@stripped, 2007-03-28 12:04:56+02:00,
knielsen@ymer.(none) +0 -0
    Merge rename: ndb/include/kernel/signaldata/ScanTab.hpp ->
storage/ndb/include/kernel/signaldata/ScanTab.hpp

  storage/ndb/include/ndbapi/NdbOperation.hpp@stripped, 2007-03-28 12:17:06+02:00,
knielsen@ymer.(none) +0 -0
    Manual merge.
    MERGE: 1.31.7.2

  storage/ndb/include/ndbapi/NdbOperation.hpp@stripped, 2007-03-28 12:04:56+02:00,
knielsen@ymer.(none) +0 -0
    Merge rename: ndb/include/ndbapi/NdbOperation.hpp ->
storage/ndb/include/ndbapi/NdbOperation.hpp

  storage/ndb/include/ndbapi/NdbScanOperation.hpp@stripped, 2007-03-28 12:17:06+02:00,
knielsen@ymer.(none) +0 -0
    Manual merge.
    MERGE: 1.32.12.2

  storage/ndb/include/ndbapi/NdbScanOperation.hpp@stripped, 2007-03-28 12:04:57+02:00,
knielsen@ymer.(none) +0 -0
    Merge rename: ndb/include/ndbapi/NdbScanOperation.hpp ->
storage/ndb/include/ndbapi/NdbScanOperation.hpp

  storage/ndb/src/ndbapi/NdbBlob.cpp@stripped, 2007-03-28 12:04:57+02:00, knielsen@ymer.(none)
+0 -0
    Auto merged
    MERGE: 1.22.14.2

  storage/ndb/src/ndbapi/NdbBlob.cpp@stripped, 2007-03-28 12:04:57+02:00,
knielsen@ymer.(none) +0 -0
    Merge rename: ndb/src/ndbapi/NdbBlob.cpp -> storage/ndb/src/ndbapi/NdbBlob.cpp

  storage/ndb/src/ndbapi/NdbOperationDefine.cpp@stripped, 2007-03-28 12:04:57+02:00,
knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.19.5.2

  storage/ndb/src/ndbapi/NdbOperationDefine.cpp@stripped, 2007-03-28 12:04:57+02:00,
knielsen@ymer.(none) +0 -0
    Merge rename: ndb/src/ndbapi/NdbOperationDefine.cpp ->
storage/ndb/src/ndbapi/NdbOperationDefine.cpp

  storage/ndb/src/ndbapi/NdbScanOperation.cpp@stripped, 2007-03-28 12:04:57+02:00,
knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.66.27.2

  storage/ndb/src/ndbapi/NdbScanOperation.cpp@stripped, 2007-03-28 12:04:57+02:00,
knielsen@ymer.(none) +0 -0
    Merge rename: ndb/src/ndbapi/NdbScanOperation.cpp ->
storage/ndb/src/ndbapi/NdbScanOperation.cpp

  storage/ndb/test/ndbapi/testBlobs.cpp@stripped, 2007-03-28 12:17:06+02:00,
knielsen@ymer.(none) +3 -3
    Manual merge.
    MERGE: 1.20.18.2

  storage/ndb/test/ndbapi/testBlobs.cpp@stripped, 2007-03-28 12:04:57+02:00,
knielsen@ymer.(none) +0 -0
    Merge rename: ndb/test/ndbapi/testBlobs.cpp ->
storage/ndb/test/ndbapi/testBlobs.cpp

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	knielsen
# Host:	ymer.(none)
# Root:	/usr/local/mysql/mysql-5.1-new-ndb-bug27370/RESYNC

--- 1.13.2.1/ndb/include/kernel/signaldata/ScanTab.hpp	2007-03-28 12:17:16 +02:00
+++ 1.18/storage/ndb/include/kernel/signaldata/ScanTab.hpp	2007-03-28 12:17:16 +02:00
@@ -84,6 +84,7 @@ private:
   static Uint8 getKeyinfoFlag(const UintR & requestInfo);
   static Uint16 getScanBatch(const UintR & requestInfo);
   static Uint8 getDistributionKeyFlag(const UintR & requestInfo);
+  static UintR getNoDiskFlag(const UintR & requestInfo);
 
   /**
    * Set:ers for requestInfo
@@ -99,6 +100,7 @@ private:
   static void setKeyinfoFlag(UintR & requestInfo, Uint32 flag);
   static void setScanBatch(Uint32& requestInfo, Uint32 sz);
   static void setDistributionKeyFlag(Uint32& requestInfo, Uint32 flag);
+  static void setNoDiskFlag(UintR & requestInfo, UintR val);
 };
 
 /**
@@ -114,10 +116,11 @@ private:
  x = Range Scan (TUX)      - 1  Bit 15
  b = Scan batch            - 10 Bit 16-25 (max 1023)
  d = Distribution key flag - 1  Bit 26
+ n = No disk flag          - 1  Bit 9
 
            1111111111222222222233
  01234567890123456789012345678901
- ppppppppl hcktzxbbbbbbbbbbd
+ pppppppplnhcktzxbbbbbbbbbbd
 */
 
 #define PARALLEL_SHIFT     (0)
@@ -150,6 +153,9 @@ private:
 #define SCAN_DISTR_KEY_SHIFT (26)
 #define SCAN_DISTR_KEY_MASK (1)
 
+#define SCAN_NODISK_SHIFT (9)
+#define SCAN_NODISK_MASK (1)
+
 inline
 Uint8
 ScanTabReq::getParallelism(const UintR & requestInfo){
@@ -294,6 +300,20 @@ ScanTabReq::setDistributionKeyFlag(UintR
   ASSERT_BOOL(flag, "ScanTabReq::setKeyinfoFlag");
   requestInfo= (requestInfo & ~(SCAN_DISTR_KEY_MASK << SCAN_DISTR_KEY_SHIFT)) |
                ((flag & SCAN_DISTR_KEY_MASK) << SCAN_DISTR_KEY_SHIFT);
+}
+
+inline
+UintR 
+ScanTabReq::getNoDiskFlag(const UintR & requestInfo){
+  return (requestInfo >> SCAN_NODISK_SHIFT) & SCAN_NODISK_MASK;
+}
+
+inline
+void 
+ScanTabReq::setNoDiskFlag(UintR & requestInfo, Uint32 flag){
+  ASSERT_BOOL(flag, "TcKeyReq::setNoDiskFlag");
+  requestInfo= (requestInfo & ~(SCAN_NODISK_MASK << SCAN_NODISK_SHIFT)) |
+               ((flag & SCAN_NODISK_MASK) << SCAN_NODISK_SHIFT);
 }
 
 /**

--- 1.31.7.1/ndb/include/ndbapi/NdbOperation.hpp	2007-03-28 12:17:16 +02:00
+++ 1.43/storage/ndb/include/ndbapi/NdbOperation.hpp	2007-03-28 12:17:16 +02:00
@@ -98,6 +98,32 @@ public:
   };
 
   /**
+   * How should transaction be handled if operation fails.
+   *
+   * If AO_IgnoreError, a failure in one operation will not abort the
+   * transaction, and NdbTransaction::execute() will return 0 (success). Use
+   * NdbOperation::getNdbError() to check for errors from individual
+   * operations.
+   *
+   * If AbortOnError, a failure in one operation will abort the transaction
+   * and cause NdbTransaction::execute() to return -1.
+   * 
+   * Abort option can be set on execute(), or in the individual operation.
+   * Setting AO_IgnoreError or AbortOnError in execute() overrides the settings
+   * on individual operations. Setting DefaultAbortOption in execute() (the
+   * default) causes individual operation settings to be used.
+   *
+   * For READ, default is AO_IgnoreError
+   *     DML,  default is AbortOnError
+   * CommittedRead does _only_ support AO_IgnoreError
+   */
+  enum AbortOption {
+    DefaultAbortOption = -1,///< Use default as specified by op-type
+    AbortOnError = 0,       ///< Abort transaction on failed operation
+    AO_IgnoreError = 2      ///< Transaction continues on failed operation
+  };
+
+  /**
    * Define the NdbOperation to be a standard operation of type insertTuple.
    * When calling NdbTransaction::execute, this operation 
    * adds a new tuple to the table.
@@ -273,28 +299,27 @@ public:
    * @note There are 10 versions of equal() with
    *       slightly different parameters.
    *
-   * @note When using equal() with a string (char *) as
-   *       second argument, the string needs to be padded with 
-   *       zeros in the following sense:
-   *       @code
-   *       // Equal needs strings to be padded with zeros
-   *       strncpy(buf, str, sizeof(buf));
-   *       NdbOperation->equal("Attr1", buf);
-   *       @endcode
-   *
-   * 
+   * @note  If attribute has fixed size, value must include all bytes.
+   *        In particular a Char must be native-blank padded.
+   *        If attribute has variable size, value must start with
+   *        1 or 2 little-endian length bytes (2 if Long*).
    * 
    * @param   anAttrName   Attribute name 
    * @param   aValue       Attribute value.
-   * @param   len          Attribute length expressed in bytes.
    * @return               -1 if unsuccessful. 
    */
-  int  equal(const char* anAttrName, const char* aValue, Uint32 len = 0);
-  int  equal(const char* anAttrName, Uint32 aValue);	
+#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
+  int  equal(const char* anAttrName, const char* aValue, Uint32 len);
+#endif
+  int  equal(const char* anAttrName, const char* aValue);
   int  equal(const char* anAttrName, Int32 aValue);	
+  int  equal(const char* anAttrName, Uint32 aValue);	
   int  equal(const char* anAttrName, Int64 aValue);	
   int  equal(const char* anAttrName, Uint64 aValue);
-  int  equal(Uint32 anAttrId, const char* aValue, Uint32 len = 0);
+#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
+  int  equal(Uint32 anAttrId, const char* aValue, Uint32 len);
+#endif
+  int  equal(Uint32 anAttrId, const char* aValue);
   int  equal(Uint32 anAttrId, Int32 aValue);	
   int  equal(Uint32 anAttrId, Uint32 aValue);	
   int  equal(Uint32 anAttrId, Int64 aValue);	
@@ -371,28 +396,34 @@ public:
    *
    * @note There are 14 versions of NdbOperation::setValue with
    *       slightly different parameters.
+   *
+   * @note See note under equal() about value format and length.
    * 
    * @param anAttrName     Name (or Id) of attribute.
    * @param aValue         Attribute value to set.
-   * @param len            Attribute length expressed in bytes.
    * @return               -1 if unsuccessful.
    */
-  virtual int  setValue(const char* anAttrName, const char* aValue, 
-			Uint32 len = 0);
-  virtual int  setValue(const char* anAttrName, Int32 aValue);
-  virtual int  setValue(const char* anAttrName, Uint32 aValue);
-  virtual int  setValue(const char* anAttrName, Uint64 aValue);
-  virtual int  setValue(const char* anAttrName, Int64 aValue);
-  virtual int  setValue(const char* anAttrName, float aValue);
-  virtual int  setValue(const char* anAttrName, double aValue);
-
-  virtual int  setValue(Uint32 anAttrId, const char* aValue, Uint32 len = 0);
-  virtual int  setValue(Uint32 anAttrId, Int32 aValue);
-  virtual int  setValue(Uint32 anAttrId, Uint32 aValue);
-  virtual int  setValue(Uint32 anAttrId, Uint64 aValue);
-  virtual int  setValue(Uint32 anAttrId, Int64 aValue);
-  virtual int  setValue(Uint32 anAttrId, float aValue);
-  virtual int  setValue(Uint32 anAttrId, double aValue);
+#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
+  int  setValue(const char* anAttrName, const char* aValue, Uint32 len);
+#endif
+  int  setValue(const char* anAttrName, const char* aValue);
+  int  setValue(const char* anAttrName, Int32 aValue);
+  int  setValue(const char* anAttrName, Uint32 aValue);
+  int  setValue(const char* anAttrName, Int64 aValue);
+  int  setValue(const char* anAttrName, Uint64 aValue);
+  int  setValue(const char* anAttrName, float aValue);
+  int  setValue(const char* anAttrName, double aValue);
+
+#ifndef DOXYGEN_SHOULD_SKIP_DEPRECATED
+  int  setValue(Uint32 anAttrId, const char* aValue, Uint32 len);
+#endif
+  int  setValue(Uint32 anAttrId, const char* aValue);
+  int  setValue(Uint32 anAttrId, Int32 aValue);
+  int  setValue(Uint32 anAttrId, Uint32 aValue);
+  int  setValue(Uint32 anAttrId, Int64 aValue);
+  int  setValue(Uint32 anAttrId, Uint64 aValue);
+  int  setValue(Uint32 anAttrId, float aValue);
+  int  setValue(Uint32 anAttrId, double aValue);
 
   /**
    * This method replaces getValue/setValue for blobs.  It creates
@@ -771,8 +802,13 @@ public:
    */
   LockMode getLockMode() const { return theLockMode; }
 
+  /**
+   * Get/set abort option
+   */
+  AbortOption getAbortOption() const;
+  int setAbortOption(AbortOption);
+  
 #ifndef DOXYGEN_SHOULD_SKIP_INTERNAL
-  void setAbortOption(Int8 ao) { m_abortOption = ao; }
   
   /**
    * Set/get partition key
@@ -851,7 +887,8 @@ protected:
 
   int    doSend(int ProcessorId, Uint32 lastFlag);
   virtual int	 prepareSend(Uint32  TC_ConnectPtr,
-                             Uint64  TransactionId);
+                             Uint64  TransactionId,
+			     AbortOption);
   virtual void   setLastFlag(NdbApiSignal* signal, Uint32 lastFlag);
     
   int	 prepareSendInterpreted();            // Help routine to prepare*
@@ -866,9 +903,9 @@ protected:
  *	These are support methods only used locally in this class.
 ******************************************************************************/
 
-  virtual int equal_impl(const NdbColumnImpl*,const char* aValue, Uint32 len);
+  virtual int equal_impl(const NdbColumnImpl*,const char* aValue);
   virtual NdbRecAttr* getValue_impl(const NdbColumnImpl*, char* aValue = 0);
-  int setValue(const NdbColumnImpl* anAttrObject, const char* aValue, Uint32 len);
+  int setValue(const NdbColumnImpl* anAttrObject, const char* aValue);
   NdbBlob* getBlobHandle(NdbTransaction* aCon, const NdbColumnImpl* anAttrObject);
   int incValue(const NdbColumnImpl* anAttrObject, Uint32 aValue);
   int incValue(const NdbColumnImpl* anAttrObject, Uint64 aValue);
@@ -887,6 +924,7 @@ protected:
   int insertKEYINFO(const char* aValue,	
 		    Uint32 aStartPosition,	
 		    Uint32 aKeyLenInByte);
+  void reorderKEYINFO();
   
   virtual void setErrorCode(int aErrorCode);
   virtual void setErrorCodeAbort(int aErrorCode);
@@ -906,7 +944,7 @@ protected:
   Uint32 ptr2int() { return theReceiver.getId(); };
 
   // get table or index key from prepared signals
-  int getKeyFromTCREQ(Uint32* data, unsigned size);
+  int getKeyFromTCREQ(Uint32* data, Uint32 & size);
 
   virtual void setLockMode(LockMode lockMode);
 
@@ -986,6 +1024,7 @@ protected:
   Uint8  theDirtyIndicator;	 // Indicator of whether dirty operation
   Uint8  theInterpretIndicator;  // Indicator of whether interpreted operation
   Int8  theDistrKeyIndicator_;    // Indicates whether distr. key is used
+  Uint8  m_no_disk_flag;          
 
   Uint16 m_tcReqGSN;
   Uint16 m_keyInfoGSN;
@@ -995,10 +1034,8 @@ protected:
   NdbBlob* theBlobList;
 
   /*
-   * Abort option per operation, used by blobs.  Default -1.  If set,
-   * overrides abort option on connection level.  If set to IgnoreError,
-   * does not cause execute() to return failure.  This is different from
-   * IgnoreError on connection level.
+   * Abort option per operation, used by blobs.
+   * See also comments on enum AbortOption.
    */
   Int8 m_abortOption;
 
@@ -1134,6 +1171,13 @@ NdbOperation::NdbCon(NdbTransaction* aNd
 
 inline
 int
+NdbOperation::equal(const char* anAttrName, const char* aValue, Uint32 len)
+{
+  return equal(anAttrName, aValue);
+}
+
+inline
+int
 NdbOperation::equal(const char* anAttrName, Int32 aPar)
 {
   return equal(anAttrName, (const char*)&aPar, (Uint32)4);
@@ -1162,6 +1206,13 @@ NdbOperation::equal(const char* anAttrNa
 
 inline
 int
+NdbOperation::equal(Uint32 anAttrId, const char* aValue, Uint32 len)
+{
+  return equal(anAttrId, aValue);
+}
+
+inline
+int
 NdbOperation::equal(Uint32 anAttrId, Int32 aPar)
 {
   return equal(anAttrId, (const char*)&aPar, (Uint32)4);
@@ -1190,6 +1241,13 @@ NdbOperation::equal(Uint32 anAttrId, Uin
 
 inline
 int
+NdbOperation::setValue(const char* anAttrName, const char* aValue, Uint32 len)
+{
+  return setValue(anAttrName, aValue);
+}
+
+inline
+int
 NdbOperation::setValue(const char* anAttrName, Int32 aPar)
 {
   return setValue(anAttrName, (const char*)&aPar, (Uint32)4);
@@ -1228,6 +1286,13 @@ int
 NdbOperation::setValue(const char* anAttrName, double aPar)
 {
   return setValue(anAttrName, (const char*)&aPar, (Uint32)8);
+}
+
+inline
+int
+NdbOperation::setValue(Uint32 anAttrId, const char* aValue, Uint32 len)
+{
+  return setValue(anAttrId, aValue);
 }
 
 inline

--- 1.32.12.1/ndb/include/ndbapi/NdbScanOperation.hpp	2007-03-28 12:17:16 +02:00
+++ 1.50/storage/ndb/include/ndbapi/NdbScanOperation.hpp	2007-03-28 12:17:16 +02:00
@@ -20,6 +20,7 @@
 
 class NdbBlob;
 class NdbResultSet;
+class PollGuard;
 
 /**
  * @class NdbScanOperation
@@ -41,7 +42,8 @@ public:
    * ranges (bounds) are to be passed.
    */
   enum ScanFlag {
-    SF_TupScan = (1 << 16),     // scan TUP
+    SF_TupScan = (1 << 16),     // scan TUP order
+    SF_DiskScan = (2 << 16),    // scan in DISK order
     SF_OrderBy = (1 << 24),     // index scan in order
     SF_Descending = (2 << 24),  // index scan in descending order
     SF_ReadRangeNo = (4 << 24), // enable @ref get_range_no
@@ -202,7 +204,8 @@ protected:
   int nextResultImpl(bool fetchAllowed = true, bool forceSend = false);
   virtual void release();
   
-  int close_impl(class TransporterFacade*, bool forceSend = false);
+  int close_impl(class TransporterFacade*, bool forceSend,
+                 PollGuard *poll_guard);
 
   // Overloaded methods from NdbCursorOperation
   int executeCursor(int ProcessorId);
@@ -211,7 +214,6 @@ protected:
   int init(const NdbTableImpl* tab, NdbTransaction*);
   int prepareSend(Uint32  TC_ConnectPtr, Uint64  TransactionId);
   int doSend(int ProcessorId);
-  void checkForceSend(bool forceSend);
   virtual void setLockMode(LockMode lockMode);
 
   virtual void setErrorCode(int aErrorCode);
@@ -254,12 +256,12 @@ protected:
   Uint32 m_sent_receivers_count;  // NOTE needs mutex to access
   NdbReceiver** m_sent_receivers; // receive thread puts them here
   
-  int send_next_scan(Uint32 cnt, bool close, bool forceSend = false);
+  int send_next_scan(Uint32 cnt, bool close);
   void receiver_delivered(NdbReceiver*);
   void receiver_completed(NdbReceiver*);
   void execCLOSE_SCAN_REP();
 
-  int getKeyFromKEYINFO20(Uint32* data, unsigned size);
+  int getKeyFromKEYINFO20(Uint32* data, Uint32 & size);
   NdbOperation*	takeOverScanOp(OperationType opType, NdbTransaction*);
   
   bool m_ordered;
@@ -267,6 +269,7 @@ protected:
   Uint32 m_read_range_no;
   NdbRecAttr *m_curr_row; // Pointer to last returned row
   bool m_multi_range; // Mark if operation is part of multi-range scan
+  bool m_executed; // Marker if operation should be released at close
 };
 
 inline

--- 1.19.5.1/ndb/src/ndbapi/NdbOperationDefine.cpp	2007-03-28 12:17:16 +02:00
+++ 1.30/storage/ndb/src/ndbapi/NdbOperationDefine.cpp	2007-03-28 12:17:16 +02:00
@@ -44,6 +44,7 @@ NdbOperation::insertTuple()
     tNdbCon->theSimpleState = 0;
     theErrorLine = tErrorLine++;
     theLockMode = LM_Exclusive;
+    m_abortOption = AbortOnError;
     return 0; 
   } else {
     setErrorCode(4200);
@@ -64,6 +65,7 @@ NdbOperation::updateTuple()
     theOperationType = UpdateRequest;  
     theErrorLine = tErrorLine++;
     theLockMode = LM_Exclusive;
+    m_abortOption = AbortOnError;
     return 0; 
   } else {
     setErrorCode(4200);
@@ -84,12 +86,35 @@ NdbOperation::writeTuple()
     theOperationType = WriteRequest;  
     theErrorLine = tErrorLine++;
     theLockMode = LM_Exclusive;
+    m_abortOption = AbortOnError;
     return 0; 
   } else {
     setErrorCode(4200);
     return -1;
   }//if
 }//NdbOperation::writeTuple()
+/*****************************************************************************
+ * int deleteTuple();
+ *****************************************************************************/
+int
+NdbOperation::deleteTuple()
+{
+  NdbTransaction* tNdbCon = theNdbCon;
+  int tErrorLine = theErrorLine;
+  if (theStatus == Init) {
+    theStatus = OperationDefined;  
+    tNdbCon->theSimpleState = 0;
+    theOperationType = DeleteRequest;
+    theErrorLine = tErrorLine++;
+    theLockMode = LM_Exclusive;
+    m_abortOption = AbortOnError;
+    return 0;
+  } else {
+    setErrorCode(4200);
+    return -1;
+  }//if
+}//NdbOperation::deleteTuple()
+
 /******************************************************************************
  * int readTuple();
  *****************************************************************************/
@@ -124,6 +149,7 @@ NdbOperation::readTuple()
     theOperationType = ReadRequest;
     theErrorLine = tErrorLine++;
     theLockMode = LM_Read;
+    m_abortOption = AO_IgnoreError;
     return 0;
   } else {
     setErrorCode(4200);
@@ -131,27 +157,6 @@ NdbOperation::readTuple()
   }//if
 }//NdbOperation::readTuple()
 
-/*****************************************************************************
- * int deleteTuple();
- *****************************************************************************/
-int
-NdbOperation::deleteTuple()
-{
-  NdbTransaction* tNdbCon = theNdbCon;
-  int tErrorLine = theErrorLine;
-  if (theStatus == Init) {
-    theStatus = OperationDefined;  
-    tNdbCon->theSimpleState = 0;
-    theOperationType = DeleteRequest;
-    theErrorLine = tErrorLine++;
-    theLockMode = LM_Exclusive;
-    return 0;
-  } else {
-    setErrorCode(4200);
-    return -1;
-  }//if
-}//NdbOperation::deleteTuple()
-
 /******************************************************************************
  * int readTupleExclusive();
  *****************************************************************************/
@@ -166,6 +171,7 @@ NdbOperation::readTupleExclusive()
     theOperationType = ReadExclusive;
     theErrorLine = tErrorLine++;
     theLockMode = LM_Exclusive;
+    m_abortOption = AO_IgnoreError;
     return 0;
   } else {
     setErrorCode(4200);
@@ -222,6 +228,7 @@ NdbOperation::committedRead()
     theDirtyIndicator = 1;
     theErrorLine = tErrorLine++;
     theLockMode = LM_CommittedRead;
+    m_abortOption = AO_IgnoreError;
     return 0;
   } else {
     setErrorCode(4200);
@@ -245,6 +252,7 @@ NdbOperation::dirtyUpdate()
     theDirtyIndicator = 1;
     theErrorLine = tErrorLine++;
     theLockMode = LM_CommittedRead;
+    m_abortOption = AbortOnError;
     return 0;
   } else {
     setErrorCode(4200);
@@ -268,6 +276,7 @@ NdbOperation::dirtyWrite()
     theDirtyIndicator = 1;
     theErrorLine = tErrorLine++;
     theLockMode = LM_CommittedRead;
+    m_abortOption = AbortOnError;
     return 0;
   } else {
     setErrorCode(4200);
@@ -290,6 +299,7 @@ NdbOperation::interpretedUpdateTuple()
     theAI_LenInCurrAI = 25;
     theLockMode = LM_Exclusive;
     theErrorLine = tErrorLine++;
+    m_abortOption = AbortOnError;
     initInterpreter();
     return 0;
   } else {
@@ -314,6 +324,7 @@ NdbOperation::interpretedDeleteTuple()
     theErrorLine = tErrorLine++;
     theAI_LenInCurrAI = 25;
     theLockMode = LM_Exclusive;
+    m_abortOption = AbortOnError;
     initInterpreter();
     return 0;
   } else {
@@ -367,6 +378,7 @@ NdbOperation::getValue_impl(const NdbCol
   NdbRecAttr* tRecAttr;
   if ((tAttrInfo != NULL) &&
       (theStatus != Init)){
+    m_no_disk_flag &= (tAttrInfo->m_storageType == NDB_STORAGETYPE_DISK ? 0:1);
     if (theStatus != GetValue) {
       if (theInterpretIndicator == 1) {
 	if (theStatus == FinalGetValue) {
@@ -431,15 +443,12 @@ NdbOperation::getValue_impl(const NdbCol
 ******************************************************************************/
 int
 NdbOperation::setValue( const NdbColumnImpl* tAttrInfo, 
-			const char* aValuePassed, Uint32 len)
+			const char* aValuePassed)
 {
   DBUG_ENTER("NdbOperation::setValue");
-  DBUG_PRINT("enter", ("col: %s  op: %d  val: 0x%lx  len: %u",
-                       tAttrInfo->m_name.c_str(),
-                       theOperationType,
-                       (long) aValuePassed, len));
-  if (aValuePassed != NULL)
-    DBUG_DUMP("value", (char*)aValuePassed, len);
+  DBUG_PRINT("enter", ("col: %s  op:%d  val: 0x%lx",
+                       tAttrInfo->m_name.c_str(), theOperationType,
+                       (long) aValuePassed));
 
   int tReturnCode;
   Uint32 tAttrId;
@@ -510,18 +519,16 @@ NdbOperation::setValue( const NdbColumnI
   }//if
   if (tAttrInfo->m_pk) {
     if (theOperationType == InsertRequest) {
-      DBUG_RETURN(equal_impl(tAttrInfo, aValuePassed, len));
+      DBUG_RETURN(equal_impl(tAttrInfo, aValuePassed));
     } else {
       setErrorCodeAbort(4202);      
       DBUG_RETURN(-1);
     }//if
   }//if
-  if (len > 8000) {
-    setErrorCodeAbort(4216);
-    DBUG_RETURN(-1);
-  }//if
   
+  // Insert Attribute Id into ATTRINFO part. 
   tAttrId = tAttrInfo->m_attrId;
+  m_no_disk_flag &= (tAttrInfo->m_storageType == NDB_STORAGETYPE_DISK ? 0:1);
   const char *aValue = aValuePassed; 
   Uint32 ahValue;
   if (aValue == NULL) {
@@ -541,35 +548,15 @@ NdbOperation::setValue( const NdbColumnI
     }//if
   }//if
   
-  // Insert Attribute Id into ATTRINFO part. 
-  const Uint32 sizeInBytes = tAttrInfo->m_attrSize * tAttrInfo->m_arraySize;
-
-#if 0
-  tAttrSize = tAttrInfo->theAttrSize;
-  tArraySize = tAttrInfo->theArraySize;
-  if (tArraySize == 0) {
-    setErrorCodeAbort(4201);      
-    return -1;
-  }//if
-  tAttrSizeInBits = tAttrSize*tArraySize;
-  tAttrSizeInWords = tAttrSizeInBits >> 5;
-#endif
-  const Uint32 bitsInLastWord = 8 * (sizeInBytes & 3) ;
-  if (len != sizeInBytes && (len != 0)) {
+  Uint32 len;
+  if (! tAttrInfo->get_var_length(aValue, len)) {
     setErrorCodeAbort(4209);
     DBUG_RETURN(-1);
-  }//if
-  const Uint32 totalSizeInWords = (sizeInBytes + 3)/4; // Including bits in last word
-  const Uint32 sizeInWords = sizeInBytes / 4;          // Excluding bits in last word
-  (void) AttributeHeader::init(&ahValue, tAttrId, totalSizeInWords);
-  insertATTRINFO( ahValue );
+  }
 
-  /***********************************************************************
-   * Check if the pointer of the value passed is aligned on a 4 byte boundary.
-   * If so only assign the pointer to the internal variable aValue. 
-   * If it is not aligned then we start by copying the value to tempData and 
-   * use this as aValue instead.
-   *************************************************************************/
+  const Uint32 sizeInBytes = len;
+  const Uint32 bitsInLastWord = 8 * (sizeInBytes & 3) ;
+  
   const int attributeSize = sizeInBytes;
   const int slack = sizeInBytes & 3;
   
@@ -582,6 +569,18 @@ NdbOperation::setValue( const NdbColumnI
     }//if
   }//if
   
+  // Excluding bits in last word
+  const Uint32 sizeInWords = sizeInBytes / 4;          
+  (void) AttributeHeader::init(&ahValue, tAttrId, sizeInBytes);
+  insertATTRINFO( ahValue );
+
+  /***********************************************************************
+   * Check if the pointer of the value passed is aligned on a 4 byte boundary.
+   * If so only assign the pointer to the internal variable aValue. 
+   * If it is not aligned then we start by copying the value to tempData and 
+   * use this as aValue instead.
+   *************************************************************************/
+  
   tReturnCode = insertATTRINFOloop((Uint32*)aValue, sizeInWords);
   if (tReturnCode == -1) {
     DBUG_RETURN(tReturnCode);
@@ -744,6 +743,22 @@ insertATTRINFO_error1:
 
 }//NdbOperation::insertATTRINFOloop()
 
+NdbOperation::AbortOption
+NdbOperation::getAbortOption() const
+{
+  return (AbortOption)m_abortOption;
+}
 
-
-
+int
+NdbOperation::setAbortOption(AbortOption ao)
+{
+  switch(ao)
+  {
+    case AO_IgnoreError:
+    case AbortOnError:
+      m_abortOption= ao;
+      return 0;
+    default:
+      return -1;
+  }
+}

--- 1.66.27.1/ndb/src/ndbapi/NdbScanOperation.cpp	2007-03-28 12:17:16 +02:00
+++ 1.113/storage/ndb/src/ndbapi/NdbScanOperation.cpp	2007-03-28 12:17:16 +02:00
@@ -49,6 +49,7 @@ NdbScanOperation::NdbScanOperation(Ndb* 
   m_receivers = 0;
   m_array = new Uint32[1]; // skip if on delete in fix_receivers
   theSCAN_TABREQ = 0;
+  m_executed = false;
 }
 
 NdbScanOperation::~NdbScanOperation()
@@ -110,6 +111,7 @@ NdbScanOperation::init(const NdbTableImp
   theNdbCon->theMagicNumber = 0xFE11DF;
   theNoOfTupKeyLeft = tab->m_noOfDistributionKeys;
   m_read_range_no = 0;
+  m_executed = false;
   return 0;
 }
 
@@ -136,9 +138,25 @@ NdbScanOperation::readTuples(NdbScanOper
   }
 
   theNdbCon->theScanningOp = this;
+  bool tupScan = (scan_flags & SF_TupScan);
 
+#if 1 // XXX temp for testing
+  { char* p = getenv("NDB_USE_TUPSCAN");
+    if (p != 0) {
+      unsigned n = atoi(p); // 0-10
+      if ((unsigned int) (::time(0) % 10) < n) tupScan = true;
+    }
+  }
+#endif
+  if (scan_flags & SF_DiskScan)
+  {
+    tupScan = true;
+    m_no_disk_flag = false;
+  }
+  
   bool rangeScan = false;
-  if (m_accessTable->m_indexType == NdbDictionary::Index::OrderedIndex)
+  if ( (int) m_accessTable->m_indexType ==
+       (int) NdbDictionary::Index::OrderedIndex)
   {
     if (m_currentTable == m_accessTable){
       // Old way of scanning indexes, should not be allowed
@@ -151,12 +169,9 @@ NdbScanOperation::readTuples(NdbScanOper
     theStatus = GetValue;
     theOperationType  = OpenRangeScanRequest;
     rangeScan = true;
-  }
-
-  bool tupScan = (scan_flags & SF_TupScan);
-  if (tupScan && rangeScan)
     tupScan = false;
-
+  }
+  
   if (rangeScan && (scan_flags & SF_OrderBy))
     parallel = fragCount;
   
@@ -176,7 +191,7 @@ NdbScanOperation::readTuples(NdbScanOper
   theSCAN_TABREQ->setSignal(GSN_SCAN_TABREQ);
   ScanTabReq * req = CAST_PTR(ScanTabReq, theSCAN_TABREQ->getDataPtrSend());
   req->apiConnectPtr = theNdbCon->theTCConPtr;
-  req->tableId = m_accessTable->m_tableId;
+  req->tableId = m_accessTable->m_id;
   req->tableSchemaVersion = m_accessTable->m_version;
   req->storedProcId = 0xFFFF;
   req->buddyConPtr = theNdbCon->theBuddyConPtr;
@@ -371,7 +386,7 @@ NdbScanOperation::getFirstATTRINFOScan()
 int
 NdbScanOperation::executeCursor(int nodeId){
   NdbTransaction * tCon = theNdbCon;
-  TransporterFacade* tp = TransporterFacade::instance();
+  TransporterFacade* tp = theNdb->theImpl->m_transporter_facade;
   Guard guard(tp->theMutexPtr);
 
   Uint32 magic = tCon->theMagicNumber;
@@ -393,6 +408,7 @@ NdbScanOperation::executeCursor(int node
     if (doSendScan(nodeId) == -1)
       return -1;
 
+    m_executed= true; // Mark operation as executed
     return 0;
   } else {
     if (!(tp->get_node_stopping(nodeId) &&
@@ -472,18 +488,28 @@ int NdbScanOperation::nextResultImpl(boo
   }
   
   Uint32 nodeId = theNdbCon->theDBnode;
-  TransporterFacade* tp = TransporterFacade::instance();
-  Guard guard(tp->theMutexPtr);
-  if(theError.code)
-    return -1;
+  TransporterFacade* tp = theNdb->theImpl->m_transporter_facade;
+  /*
+    The PollGuard has an implicit call of unlock_and_signal through the
+    ~PollGuard method. This method is called implicitly by the compiler
+    in all places where the object is out of context due to a return,
+    break, continue or simply end of statement block
+  */
+  PollGuard poll_guard(tp, &theNdb->theImpl->theWaiter,
+                       theNdb->theNdbBlockNumber);
 
-  Uint32 seq = theNdbCon->theNodeSequence;
-  if(seq == tp->getNodeSequence(nodeId) && send_next_scan(idx, false,
-							  forceSend) == 0){
+  const Uint32 seq = theNdbCon->theNodeSequence;
+
+  if(theError.code)
+  {
+    goto err4;
+  }
+  
+  if(seq == tp->getNodeSequence(nodeId) && send_next_scan(idx, false) == 0)
+  {
       
     idx = m_current_api_receiver;
     last = m_api_receivers_count;
-
     Uint32 timeout = tp->m_waitfor_timeout;
       
     do {
@@ -510,12 +536,10 @@ int NdbScanOperation::nextResultImpl(boo
 	/**
 	 * No completed...
 	 */
-	theNdb->theImpl->theWaiter.m_node = nodeId;
-	theNdb->theImpl->theWaiter.m_state = WAIT_SCAN;
-	int return_code = theNdb->receiveResponse(3*timeout);
-	if (return_code == 0 && seq == tp->getNodeSequence(nodeId)) {
+        int ret_code= poll_guard.wait_scan(3*timeout, nodeId, forceSend);
+	if (ret_code == 0 && seq == tp->getNodeSequence(nodeId)) {
 	  continue;
-	} else if(return_code == -1){
+	} else if(ret_code == -1){
 	  retVal = -1;
 	} else {
 	  idx = last;
@@ -565,17 +589,21 @@ int NdbScanOperation::nextResultImpl(boo
     if(theError.code == 0)
       setErrorCode(4028); // seq changed = Node fail
     break;
+  case -4:
+err4:
+    setErrorCode(theError.code);
+    break;
   }
     
   theNdbCon->theTransactionIsStarted = false;
   theNdbCon->theReleaseOnClose = true;
-  if(DEBUG_NEXT_RESULT) ndbout_c("return -1", retVal);
+  if(DEBUG_NEXT_RESULT) ndbout_c("return %d", retVal);
   return -1;
 }
 
 int
-NdbScanOperation::send_next_scan(Uint32 cnt, bool stopScanFlag,
-				 bool forceSend){  
+NdbScanOperation::send_next_scan(Uint32 cnt, bool stopScanFlag)
+{
   if(cnt > 0){
     NdbApiSignal tSignal(theNdb->theMyRef);
     tSignal.setSignal(GSN_SCAN_NEXTREQ);
@@ -610,7 +638,7 @@ NdbScanOperation::send_next_scan(Uint32 
     if(sent)
     {
       Uint32 nodeId = theNdbCon->theDBnode;
-      TransporterFacade * tp = TransporterFacade::instance();
+      TransporterFacade * tp = theNdb->theImpl->m_transporter_facade;
       if(cnt > 21){
 	tSignal.setLength(4);
 	LinearSectionPtr ptr[3];
@@ -622,9 +650,6 @@ NdbScanOperation::send_next_scan(Uint32 
 	ret = tp->sendSignal(&tSignal, nodeId);
       }
     }
-    
-    if (!ret) checkForceSend(forceSend);
-
     m_sent_receivers_count = last + sent;
     m_api_receivers_count -= cnt;
     m_current_api_receiver = 0;
@@ -634,15 +659,6 @@ NdbScanOperation::send_next_scan(Uint32 
   return 0;
 }
 
-void NdbScanOperation::checkForceSend(bool forceSend)
-{
-  if (forceSend) {
-    TransporterFacade::instance()->forceSend(theNdb->theNdbBlockNumber);
-  } else {
-    TransporterFacade::instance()->checkForceSend(theNdb->theNdbBlockNumber);
-  }//if
-}
-
 int 
 NdbScanOperation::prepareSend(Uint32  TC_ConnectPtr, Uint64  TransactionId)
 {
@@ -662,8 +678,8 @@ void NdbScanOperation::close(bool forceS
 {
   DBUG_ENTER("NdbScanOperation::close");
   DBUG_PRINT("enter", ("this: 0x%lx  tcon: 0x%lx  con: 0x%lx  force: %d  release: %d",
-                       (long)this,
-                       (long)m_transConnection, (long)theNdbCon,
+                       (long) this,
+                       (long) m_transConnection, (long) theNdbCon,
                        forceSend, releaseOp));
 
   if(m_transConnection){
@@ -677,10 +693,16 @@ void NdbScanOperation::close(bool forceS
 	       m_conf_receivers_count,
 	       m_sent_receivers_count);
     
-    TransporterFacade* tp = TransporterFacade::instance();
-    Guard guard(tp->theMutexPtr);
-    close_impl(tp, forceSend);
-    
+    TransporterFacade* tp = theNdb->theImpl->m_transporter_facade;
+    /*
+      The PollGuard has an implicit call of unlock_and_signal through the
+      ~PollGuard method. This method is called implicitly by the compiler
+      in all places where the object is out of context due to a return,
+      break, continue or simply end of statement block
+    */
+    PollGuard poll_guard(tp, &theNdb->theImpl->theWaiter,
+                         theNdb->theNdbBlockNumber);
+    close_impl(tp, forceSend, &poll_guard);
   }
 
   NdbConnection* tCon = theNdbCon;
@@ -803,6 +825,7 @@ int NdbScanOperation::prepareSendScan(Ui
    */
   Uint32 reqInfo = req->requestInfo;
   ScanTabReq::setKeyinfoFlag(reqInfo, keyInfo);
+  ScanTabReq::setNoDiskFlag(reqInfo, m_no_disk_flag);
   req->requestInfo = reqInfo;
   
   for(Uint32 i = 0; i<theParallelism; i++){
@@ -852,7 +875,7 @@ NdbScanOperation::doSendScan(int aProces
   req->requestInfo = tmp;
   tSignal->setLength(ScanTabReq::StaticLength + theDistrKeyIndicator_);
 
-  TransporterFacade *tp = TransporterFacade::instance();
+  TransporterFacade *tp = theNdb->theImpl->m_transporter_facade;
   LinearSectionPtr ptr[3];
   ptr[0].p = m_prepared_receivers;
   ptr[0].sz = theParallelism;
@@ -936,13 +959,20 @@ NdbScanOperation::doSendScan(int aProces
  *     the scan process. 
  ****************************************************************************/
 int
-NdbScanOperation::getKeyFromKEYINFO20(Uint32* data, unsigned size)
+NdbScanOperation::getKeyFromKEYINFO20(Uint32* data, Uint32 & size)
 {
   NdbRecAttr * tRecAttr = m_curr_row;
   if(tRecAttr)
   {
     const Uint32 * src = (Uint32*)tRecAttr->aRef();
-    memcpy(data, src, 4*size);
+
+    assert(tRecAttr->get_size_in_bytes() > 0);
+    assert(tRecAttr->get_size_in_bytes() < 65536);
+    const Uint32 len = (tRecAttr->get_size_in_bytes() + 3)/4-1;
+
+    assert(size >= len);
+    memcpy(data, src, 4*len);
+    size = len;
     return 0;
   }
   return -1;
@@ -967,10 +997,13 @@ NdbScanOperation::takeOverScanOp(Operati
     }
     pTrans->theSimpleState = 0;
     
-    const Uint32 len = (tRecAttr->attrSize() * tRecAttr->arraySize() + 3)/4-1;
-
+    assert(tRecAttr->get_size_in_bytes() > 0);
+    assert(tRecAttr->get_size_in_bytes() < 65536);
+    const Uint32 len = (tRecAttr->get_size_in_bytes() + 3)/4-1;
+    
     newOp->theTupKeyLen = len;
     newOp->theOperationType = opType;
+    newOp->m_abortOption = AbortOnError;
     switch (opType) {
     case (ReadRequest):
       newOp->theLockMode = theLockMode;
@@ -1066,23 +1099,23 @@ NdbIndexScanOperation::~NdbIndexScanOper
 
 int
 NdbIndexScanOperation::setBound(const char* anAttrName, int type, 
-				const void* aValue, Uint32 len)
+				const void* aValue)
 {
-  return setBound(m_accessTable->getColumn(anAttrName), type, aValue, len);
+  return setBound(m_accessTable->getColumn(anAttrName), type, aValue);
 }
 
 int
 NdbIndexScanOperation::setBound(Uint32 anAttrId, int type, 
-				const void* aValue, Uint32 len)
+				const void* aValue)
 {
-  return setBound(m_accessTable->getColumn(anAttrId), type, aValue, len);
+  return setBound(m_accessTable->getColumn(anAttrId), type, aValue);
 }
 
 int
 NdbIndexScanOperation::equal_impl(const NdbColumnImpl* anAttrObject, 
-				  const char* aValue, 
-				  Uint32 len){
-  return setBound(anAttrObject, BoundEQ, aValue, len);
+				  const char* aValue)
+{
+  return setBound(anAttrObject, BoundEQ, aValue);
 }
 
 NdbRecAttr*
@@ -1092,7 +1125,7 @@ NdbIndexScanOperation::getValue_impl(con
     return NdbScanOperation::getValue_impl(attrInfo, aValue);
   }
   
-  int id = attrInfo->m_attrId;                // In "real" table
+  int id = attrInfo->getColumnNo();                // In "real" table
   assert(m_accessTable->m_index);
   int sz = (int)m_accessTable->m_index->m_key_ids.size();
   if(id >= sz || (id = m_accessTable->m_index->m_key_ids[id]) == -1){
@@ -1129,7 +1162,7 @@ NdbIndexScanOperation::getValue_impl(con
  */
 int
 NdbIndexScanOperation::setBound(const NdbColumnImpl* tAttrInfo, 
-				int type, const void* aValue, Uint32 len)
+				int type, const void* aValue)
 {
   if (!tAttrInfo)
   {
@@ -1137,24 +1170,23 @@ NdbIndexScanOperation::setBound(const Nd
     return -1;
   }
   if (theOperationType == OpenRangeScanRequest &&
-      (0 <= type && type <= 4) &&
-      len <= 8000) {
+      (0 <= type && type <= 4)) {
     // insert bound type
     Uint32 currLen = theTotalNrOfKeyWordInSignal;
     Uint32 remaining = KeyInfo::DataLength - currLen;
-    Uint32 sizeInBytes = tAttrInfo->m_attrSize * tAttrInfo->m_arraySize;
     bool tDistrKey = tAttrInfo->m_distributionKey;
 
-    len = aValue != NULL ? sizeInBytes : 0;
-    if (len != sizeInBytes && (len != 0)) {
-      setErrorCodeAbort(4209);
-      return -1;
-    }
+    Uint32 len = 0;
+    if (aValue != NULL)
+      if (! tAttrInfo->get_var_length(aValue, len)) {
+        setErrorCodeAbort(4209);
+        return -1;
+      }
 
     // insert attribute header
     Uint32 tIndexAttrId = tAttrInfo->m_attrId;
     Uint32 sizeInWords = (len + 3) / 4;
-    AttributeHeader ah(tIndexAttrId, sizeInWords);
+    AttributeHeader ah(tIndexAttrId, sizeInWords << 2);
     const Uint32 ahValue = ah.m_value;
 
     const Uint32 align = (UintPtr(aValue) & 7);
@@ -1164,25 +1196,31 @@ NdbIndexScanOperation::setBound(const Nd
     const bool nobytes = (len & 0x3) == 0;
     const Uint32 totalLen = 2 + sizeInWords;
     Uint32 tupKeyLen = theTupKeyLen;
+    union {
+      Uint32 tempData[2000];
+      Uint64 __align;
+    };
+    Uint64 *valPtr;
     if(remaining > totalLen && aligned && nobytes){
       Uint32 * dst = theKEYINFOptr + currLen;
       * dst ++ = type;
       * dst ++ = ahValue;
       memcpy(dst, aValue, 4 * sizeInWords);
       theTotalNrOfKeyWordInSignal = currLen + totalLen;
+      valPtr = (Uint64*)aValue;
     } else {
       if(!aligned || !nobytes){
-        Uint32 tempData[2000];
 	tempData[0] = type;
 	tempData[1] = ahValue;
 	tempData[2 + (len >> 2)] = 0;
         memcpy(tempData+2, aValue, len);
-	
 	insertBOUNDS(tempData, 2+sizeInWords);
+	valPtr = (Uint64*)(tempData+2);
       } else {
 	Uint32 buf[2] = { type, ahValue };
 	insertBOUNDS(buf, 2);
 	insertBOUNDS((Uint32*)aValue, sizeInWords);
+	valPtr = (Uint64*)aValue;
       }
     }
     theTupKeyLen = tupKeyLen + totalLen;
@@ -1199,7 +1237,7 @@ NdbIndexScanOperation::setBound(const Nd
     if(type == BoundEQ && tDistrKey && !m_multi_range)
     {
       theNoOfTupKeyLeft--;
-      return handle_distribution_key((Uint64*)aValue, sizeInWords);
+      return handle_distribution_key(valPtr, sizeInWords);
     }
     return 0;
   } else {
@@ -1248,6 +1286,31 @@ error:
   return -1;
 }
 
+Uint32
+NdbIndexScanOperation::getKeyFromSCANTABREQ(Uint32* data, Uint32 size)
+{
+  DBUG_ENTER("NdbIndexScanOperation::getKeyFromSCANTABREQ");
+  assert(size >= theTotalNrOfKeyWordInSignal);
+  size = theTotalNrOfKeyWordInSignal;
+  NdbApiSignal* tSignal = theSCAN_TABREQ->next();
+  Uint32 pos = 0;
+  while (pos < size) {
+    assert(tSignal != NULL);
+    Uint32* tData = tSignal->getDataPtrSend();
+    Uint32 rem = size - pos;
+    if (rem > KeyInfo::DataLength)
+      rem = KeyInfo::DataLength;
+    Uint32 i = 0;
+    while (i < rem) {
+      data[pos + i] = tData[KeyInfo::HeaderLength + i];
+      i++;
+    }
+    pos += rem;
+  }
+  DBUG_DUMP("key", (char*)data, size << 2);
+  DBUG_RETURN(size);
+}
+
 int
 NdbIndexScanOperation::readTuples(LockMode lm,
 				  Uint32 scan_flags,
@@ -1346,10 +1409,11 @@ NdbIndexScanOperation::compare(Uint32 sk
       return (r1_null ? -1 : 1) * jdir;
     }
     const NdbColumnImpl & col = NdbColumnImpl::getImpl(* r1->m_column);
-    Uint32 len = r1->theAttrSize * r1->theArraySize;
+    Uint32 len1 = r1->get_size_in_bytes();
+    Uint32 len2 = r2->get_size_in_bytes();
     if(!r1_null){
       const NdbSqlUtil::Type& sqlType = NdbSqlUtil::getType(col.m_type);
-      int r = (*sqlType.m_cmp)(col.m_cs, d1, len, d2, len, true);
+      int r = (*sqlType.m_cmp)(col.m_cs, d1, len1, d2, len2, true);
       if(r){
 	assert(r != NdbSqlUtil::CmpUnknown);
 	return r * jdir;
@@ -1387,26 +1451,31 @@ NdbIndexScanOperation::next_result_order
   if(fetchNeeded){
     if(fetchAllowed){
       if(DEBUG_NEXT_RESULT) ndbout_c("performing fetch...");
-      TransporterFacade* tp = TransporterFacade::instance();
-      Guard guard(tp->theMutexPtr);
+      TransporterFacade* tp = theNdb->theImpl->m_transporter_facade;
+      /*
+        The PollGuard has an implicit call of unlock_and_signal through the
+        ~PollGuard method. This method is called implicitly by the compiler
+        in all places where the object is out of context due to a return,
+        break, continue or simply end of statement block
+      */
+      PollGuard poll_guard(tp, &theNdb->theImpl->theWaiter,
+                           theNdb->theNdbBlockNumber);
       if(theError.code)
 	return -1;
       Uint32 seq = theNdbCon->theNodeSequence;
       Uint32 nodeId = theNdbCon->theDBnode;
       Uint32 timeout = tp->m_waitfor_timeout;
       if(seq == tp->getNodeSequence(nodeId) &&
-	 !send_next_scan_ordered(s_idx, forceSend)){
+	 !send_next_scan_ordered(s_idx)){
 	Uint32 tmp = m_sent_receivers_count;
 	s_idx = m_current_api_receiver; 
 	while(m_sent_receivers_count > 0 && !theError.code){
-	  theNdb->theImpl->theWaiter.m_node = nodeId;
-	  theNdb->theImpl->theWaiter.m_state = WAIT_SCAN;
-	  int return_code = theNdb->receiveResponse(3*timeout);
-	  if (return_code == 0 && seq == tp->getNodeSequence(nodeId)) {
+          int ret_code= poll_guard.wait_scan(3*timeout, nodeId, forceSend);
+	  if (ret_code == 0 && seq == tp->getNodeSequence(nodeId)) {
 	    continue;
 	  }
 	  if(DEBUG_NEXT_RESULT) ndbout_c("return -1");
-	  if(return_code == -1){
+	  if(ret_code == -1){
 	    setErrorCode(4008);
 	  } else {
 	    setErrorCode(4028);
@@ -1493,7 +1562,8 @@ NdbIndexScanOperation::next_result_order
 }
 
 int
-NdbIndexScanOperation::send_next_scan_ordered(Uint32 idx, bool forceSend){  
+NdbIndexScanOperation::send_next_scan_ordered(Uint32 idx)
+{
   if(idx == theParallelism)
     return 0;
   
@@ -1528,15 +1598,16 @@ NdbIndexScanOperation::send_next_scan_or
   m_sent_receivers_count = last + 1;
   
   Uint32 nodeId = theNdbCon->theDBnode;
-  TransporterFacade * tp = TransporterFacade::instance();
+  TransporterFacade * tp = theNdb->theImpl->m_transporter_facade;
   tSignal.setLength(4+1);
   int ret= tp->sendSignal(&tSignal, nodeId);
-  if (!ret) checkForceSend(forceSend);
   return ret;
 }
 
 int
-NdbScanOperation::close_impl(TransporterFacade* tp, bool forceSend){
+NdbScanOperation::close_impl(TransporterFacade* tp, bool forceSend,
+                             PollGuard *poll_guard)
+{
   Uint32 seq = theNdbCon->theNodeSequence;
   Uint32 nodeId = theNdbCon->theDBnode;
   
@@ -1547,15 +1618,12 @@ NdbScanOperation::close_impl(Transporter
   }
   
   Uint32 timeout = tp->m_waitfor_timeout;
-
   /**
    * Wait for outstanding
    */
   while(theError.code == 0 && m_sent_receivers_count)
   {
-    theNdb->theImpl->theWaiter.m_node = nodeId;
-    theNdb->theImpl->theWaiter.m_state = WAIT_SCAN;
-    int return_code = theNdb->receiveResponse(3*timeout);
+    int return_code= poll_guard->wait_scan(3*timeout, nodeId, forceSend);
     switch(return_code){
     case 0:
       break;
@@ -1612,7 +1680,7 @@ NdbScanOperation::close_impl(Transporter
   }
   
   // Send close scan
-  if(send_next_scan(api+conf, true, forceSend) == -1)
+  if(send_next_scan(api+conf, true) == -1)
   {
     theNdbCon->theReleaseOnClose = true;
     return -1;
@@ -1623,9 +1691,7 @@ NdbScanOperation::close_impl(Transporter
    */
   while(m_sent_receivers_count+m_api_receivers_count+m_conf_receivers_count)
   {
-    theNdb->theImpl->theWaiter.m_node = nodeId;
-    theNdb->theImpl->theWaiter.m_state = WAIT_SCAN;
-    int return_code = theNdb->receiveResponse(3*timeout);
+    int return_code= poll_guard->wait_scan(3*timeout, nodeId, forceSend);
     switch(return_code){
     case 0:
       break;
@@ -1664,13 +1730,20 @@ int
 NdbScanOperation::restart(bool forceSend)
 {
   
-  TransporterFacade* tp = TransporterFacade::instance();
-  Guard guard(tp->theMutexPtr);
+  TransporterFacade* tp = theNdb->theImpl->m_transporter_facade;
+  /*
+    The PollGuard has an implicit call of unlock_and_signal through the
+    ~PollGuard method. This method is called implicitly by the compiler
+    in all places where the object is out of context due to a return,
+    break, continue or simply end of statement block
+  */
+  PollGuard poll_guard(tp, &theNdb->theImpl->theWaiter,
+                       theNdb->theNdbBlockNumber);
   Uint32 nodeId = theNdbCon->theDBnode;
   
   {
     int res;
-    if((res= close_impl(tp, forceSend)))
+    if((res= close_impl(tp, forceSend, &poll_guard)))
     {
       return res;
     }
@@ -1684,7 +1757,6 @@ NdbScanOperation::restart(bool forceSend
   theError.code = 0;
   if (doSendScan(nodeId) == -1)
     return -1;
-  
   return 0;
 }
 
@@ -1693,9 +1765,16 @@ NdbIndexScanOperation::reset_bounds(bool
   int res;
   
   {
-    TransporterFacade* tp = TransporterFacade::instance();
-    Guard guard(tp->theMutexPtr);
-    res= close_impl(tp, forceSend);
+    TransporterFacade* tp = theNdb->theImpl->m_transporter_facade;
+    /*
+      The PollGuard has an implicit call of unlock_and_signal through the
+      ~PollGuard method. This method is called implicitly by the compiler
+      in all places where the object is out of context due to a return,
+      break, continue or simply end of statement block
+    */
+    PollGuard poll_guard(tp, &theNdb->theImpl->theWaiter,
+                         theNdb->theNdbBlockNumber);
+    res= close_impl(tp, forceSend, &poll_guard);
   }
 
   if(!res)

--- 1.20.18.1/ndb/test/ndbapi/testBlobs.cpp	2007-03-28 12:17:16 +02:00
+++ 1.39/storage/ndb/test/ndbapi/testBlobs.cpp	2007-03-28 12:17:16 +02:00
@@ -123,25 +123,25 @@ printusage()
     << "metadata" << endl
     << "  -pk2len N   length of PK2 [" << d.m_pk2len << "/" <<
g_max_pk2len <<"]" << endl
     << "  -oneblob    only 1 blob attribute [default 2]" << endl
-    << "testcases for test/skip" << endl
+    << "test cases for test/skip" << endl
     << "  k           primary key ops" << endl
     << "  i           hash index ops" << endl
     << "  s           table scans" << endl
     << "  r           ordered index scans" << endl
     << "  p           performance test" << endl
-    << "additional flags for test/skip" << endl
+    << "operations for test/skip" << endl
     << "  u           update existing blob value" << endl
     << "  n           normal insert and update" << endl
     << "  w           insert and update using writeTuple" << endl
+    << "blob operation styles for test/skip" << endl
     << "  0           getValue / setValue" << endl
     << "  1           setActiveHook" << endl
     << "  2           readData / writeData" << endl
-    << "bug tests (no blob test)" << endl
+    << "example: -test kn0 (need all 3 parts)" << endl
+    << "bug tests" << endl
     << "  -bug 4088   ndb api hang with mixed ops on index table" << endl
     << "  -bug 27018  middle partial part write clobbers rest of part" <<
endl
     << "  -bug 27370  middle partial part write clobbers rest of part" <<
endl
-    << "  -bug nnnn   delete + write gives 626" << endl
-    << "  -bug nnnn   acc crash on delete and long key" << endl
     ;
 }
 
@@ -736,7 +736,7 @@ verifyHeadInline(const Tup& tup)
   if (! g_opt.m_oneblob)
     CHK((ra2 = g_opr->getValue("BL2")) != 0);
   if (tup.m_exists) {
-    CHK(g_con->execute(Commit) == 0);
+    CHK(g_con->execute(Commit, AbortOnError) == 0);
     DBG("verifyHeadInline BL1");
     CHK(verifyHeadInline(g_opt.m_blob1, tup.m_blob1, ra1) == 0);
     if (! g_opt.m_oneblob) {
@@ -744,7 +744,8 @@ verifyHeadInline(const Tup& tup)
       CHK(verifyHeadInline(g_opt.m_blob2, tup.m_blob2, ra2) == 0);
     }
   } else {
-    CHK(g_con->execute(Commit) == -1 && g_con->getNdbError().code == 626);
+    CHK(g_con->execute(Commit, AbortOnError) == -1 && 
+	g_con->getNdbError().code == 626);
   }
   g_ndb->closeTransaction(g_con);
   g_opr = 0;
@@ -1029,6 +1030,32 @@ deletePk()
   return 0;
 }
 
+static int
+deleteNoPk()
+{
+  DBG("--- deleteNoPk ---");
+  Tup no_tup; // bug#24028
+  no_tup.m_pk1 = 0xb1ffb1ff;
+  sprintf(no_tup.m_pk2, "%-*.*s", g_opt.m_pk2len, g_opt.m_pk2len,  "b1ffb1ff");
+  CHK((g_con = g_ndb->startTransaction()) != 0);
+  Tup& tup =  no_tup;
+  DBG("deletePk pk1=" << hex << tup.m_pk1);
+  CHK((g_opr = g_con->getNdbOperation(g_opt.m_tname)) != 0);
+  CHK(g_opr->deleteTuple() == 0);
+  CHK(g_opr->equal("PK1", tup.m_pk1) == 0);
+  if (g_opt.m_pk2len != 0)
+    CHK(g_opr->equal("PK2", tup.m_pk2) == 0);
+  CHK(g_con->execute(Commit) == -1); // fail
+  // BUG: error should be on op but is on con now
+  DBG("con: " << g_con->getNdbError());
+  DBG("opr: " << g_opr->getNdbError());
+  CHK(g_con->getNdbError().code == 626 || g_opr->getNdbError().code == 626);
+  g_ndb->closeTransaction(g_con);
+  g_opr = 0;
+  g_con = 0;
+  return 0;
+}
+
 // hash index ops
 
 static int
@@ -1384,6 +1411,7 @@ testmain()
           CHK(readPk(style) == 0);
         }
         CHK(deletePk() == 0);
+        CHK(deleteNoPk() == 0);
         CHK(verifyBlob() == 0);
       }
       if (testcase('w')) {
@@ -1398,6 +1426,7 @@ testmain()
           CHK(readPk(style) == 0);
         }
         CHK(deletePk() == 0);
+        CHK(deleteNoPk() == 0);
         CHK(verifyBlob() == 0);
       }
     }
@@ -1536,7 +1565,7 @@ testperf()
   g_dic = g_ndb->getDictionary();
   NdbDictionary::Table tab(g_opt.m_tnameperf);
   if (g_dic->getTable(tab.getName()) != 0)
-    CHK(g_dic->dropTable(tab) == 0);
+    CHK(g_dic->dropTable(tab.getName()) == 0);
   // col A - pk
   { NdbDictionary::Column col("A");
     col.setType(NdbDictionary::Column::Unsigned);
@@ -2052,18 +2081,6 @@ bugtest_27370()
   g_con= NULL;
   g_opr= NULL;
   g_bh1= NULL;
-  return 0;
-}
-
-static int
-bugtest_2222()
-{
-  return 0;
-}
-
-static int
-bugtest_3333()
-{
   return 0;
 }
 

--- 1.22.14.1/ndb/src/ndbapi/NdbBlob.cpp	2007-03-28 12:17:16 +02:00
+++ 1.56/storage/ndb/src/ndbapi/NdbBlob.cpp	2007-03-28 12:17:16 +02:00
@@ -23,6 +23,7 @@
 #include "NdbBlobImpl.hpp"
 #include <NdbScanOperation.hpp>
 #include <signaldata/TcKeyReq.hpp>
+#include <NdbEventOperationImpl.hpp>
 
 /*
  * Reading index table directly (as a table) is faster but there are
@@ -30,7 +31,21 @@
  */
 static const bool g_ndb_blob_ok_to_read_index_table = false;
 
-// state (inline)
+// get state
+
+NdbBlob::State
+NdbBlob::getState()
+{
+  return theState;
+}
+
+void
+NdbBlob::getVersion(int& version)
+{
+  version = theEventBlobVersion;
+}
+
+// set state (inline)
 
 inline void
 NdbBlob::setState(State newState)
@@ -46,32 +61,72 @@ NdbBlob::setState(State newState)
 int
 NdbBlob::getBlobTableName(char* btname, Ndb* anNdb, const char* tableName, const char*
columnName)
 {
+  DBUG_ENTER("NdbBlob::getBlobTableName");
   NdbTableImpl* t = anNdb->theDictionary->m_impl.getTable(tableName);
   if (t == NULL)
-    return -1;
+    DBUG_RETURN(-1);
   NdbColumnImpl* c = t->getColumn(columnName);
   if (c == NULL)
-    return -1;
+    DBUG_RETURN(-1);
   getBlobTableName(btname, t, c);
-  return 0;
+  DBUG_RETURN(0);
 }
 
 void
 NdbBlob::getBlobTableName(char* btname, const NdbTableImpl* t, const NdbColumnImpl* c)
 {
-  assert(t != 0 && c != 0 && c->getBlobType());
+  DBUG_ENTER("NdbBlob::getBlobTableName");
+  assert(t != 0 && c != 0 && c->getBlobType() &&
c->getPartSize() != 0);
   memset(btname, 0, NdbBlobImpl::BlobTableNameSize);
-  sprintf(btname, "NDB$BLOB_%d_%d", (int)t->m_tableId, (int)c->m_attrId);
+  sprintf(btname, "NDB$BLOB_%d_%d", (int)t->m_id, (int)c->m_column_no);
+  DBUG_PRINT("info", ("blob table name: %s", btname));
+  DBUG_VOID_RETURN;
 }
 
 void
 NdbBlob::getBlobTable(NdbTableImpl& bt, const NdbTableImpl* t, const NdbColumnImpl*
c)
 {
+  DBUG_ENTER("NdbBlob::getBlobTable");
   char btname[NdbBlobImpl::BlobTableNameSize];
   getBlobTableName(btname, t, c);
   bt.setName(btname);
   bt.setLogging(t->getLogging());
-  bt.setFragmentType(t->getFragmentType());
+  /*
+    BLOB tables use the same fragmentation as the original table
+    but may change the fragment type if it is UserDefined since it
+    must be hash based so that the kernel can handle it on its own.
+    It also uses the same tablespaces and it never uses any range or
+    list arrays.
+  */
+  bt.m_primaryTableId = t->m_id;
+  bt.m_fd.clear();
+  bt.m_ts.clear();
+  bt.m_range.clear();
+  bt.setFragmentCount(t->getFragmentCount());
+  bt.m_tablespace_id = t->m_tablespace_id;
+  bt.m_tablespace_version = t->m_tablespace_version;
+  switch (t->getFragmentType())
+  {
+    case NdbDictionary::Object::FragAllSmall:
+    case NdbDictionary::Object::FragAllMedium:
+    case NdbDictionary::Object::FragAllLarge:
+    case NdbDictionary::Object::FragSingle:
+      bt.setFragmentType(t->getFragmentType());
+      break;
+    case NdbDictionary::Object::DistrKeyLin:
+    case NdbDictionary::Object::DistrKeyHash:
+      bt.setFragmentType(t->getFragmentType());
+      break;
+    case NdbDictionary::Object::UserDefined:
+      bt.setFragmentType(NdbDictionary::Object::DistrKeyHash);
+      break;
+    default:
+      DBUG_ASSERT(0);
+      break;
+  }
+  DBUG_PRINT("info",
+  ("Create BLOB table with primary table = %u and Fragment Type = %u",
+    bt.m_primaryTableId, (uint)bt.getFragmentType()));
   { NdbDictionary::Column bc("PK");
     bc.setType(NdbDictionary::Column::Unsigned);
     assert(t->m_keyLenInWords != 0);
@@ -105,8 +160,67 @@ NdbBlob::getBlobTable(NdbTableImpl& bt, 
       break;
     }
     bc.setLength(c->getPartSize());
+    bc.setStorageType(c->getStorageType());
     bt.addColumn(bc);
   }
+  DBUG_VOID_RETURN;
+}
+
+int
+NdbBlob::getBlobEventName(char* bename, Ndb* anNdb, const char* eventName, const char*
columnName)
+{
+  NdbEventImpl* e = anNdb->theDictionary->m_impl.getEvent(eventName);
+  if (e == NULL)
+    return -1;
+  NdbColumnImpl* c = e->m_tableImpl->getColumn(columnName);
+  if (c == NULL)
+    return -1;
+  getBlobEventName(bename, e, c);
+  delete e; // it is from new NdbEventImpl
+  return 0;
+}
+
+void
+NdbBlob::getBlobEventName(char* bename, const NdbEventImpl* e, const NdbColumnImpl* c)
+{
+  // XXX events should have object id
+  snprintf(bename, MAX_TAB_NAME_SIZE, "NDB$BLOBEVENT_%s_%d", e->m_name.c_str(),
(int)c->m_column_no);
+}
+
+void
+NdbBlob::getBlobEvent(NdbEventImpl& be, const NdbEventImpl* e, const NdbColumnImpl*
c)
+{
+  DBUG_ENTER("NdbBlob::getBlobEvent");
+  // blob table
+  assert(c->m_blobTable != NULL);
+  const NdbTableImpl& bt = *c->m_blobTable;
+  // blob event name
+  char bename[MAX_TAB_NAME_SIZE+1];
+  getBlobEventName(bename, e, c);
+  bename[sizeof(bename)-1]= 0;
+  be.setName(bename);
+  be.setTable(bt);
+  // simple assigments
+  be.mi_type = e->mi_type;
+  be.m_dur = e->m_dur;
+  be.m_mergeEvents = e->m_mergeEvents;
+  // report unchanged data
+  // not really needed now since UPD is DEL o INS and we subscribe to all
+  be.setReport(NdbDictionary::Event::ER_ALL);
+  // columns PK - DIST - PART - DATA
+  { const NdbColumnImpl* bc = bt.getColumn((Uint32)0);
+    be.addColumn(*bc);
+  }
+  { const NdbColumnImpl* bc = bt.getColumn((Uint32)1);
+    be.addColumn(*bc);
+  }
+  { const NdbColumnImpl* bc = bt.getColumn((Uint32)2);
+    be.addColumn(*bc);
+  }
+  { const NdbColumnImpl* bc = bt.getColumn((Uint32)3);
+    be.addColumn(*bc);
+  }
+  DBUG_VOID_RETURN;
 }
 
 // initialization
@@ -120,9 +234,16 @@ void
 NdbBlob::init()
 {
   theState = Idle;
+  theEventBlobVersion = -1;
   theNdb = NULL;
   theNdbCon = NULL;
   theNdbOp = NULL;
+  theEventOp = NULL;
+  theBlobEventOp = NULL;
+  theBlobEventPkRecAttr = NULL;
+  theBlobEventDistRecAttr = NULL;
+  theBlobEventPartRecAttr = NULL;
+  theBlobEventDataRecAttr = NULL;
   theTable = NULL;
   theAccessTable = NULL;
   theBlobTable = NULL;
@@ -188,9 +309,16 @@ NdbBlob::Buf::alloc(unsigned n)
 }
 
 void
+NdbBlob::Buf::zerorest()
+{
+  assert(size <= maxsize);
+  memset(data + size, 0, maxsize - size);
+}
+
+void
 NdbBlob::Buf::copyfrom(const NdbBlob::Buf& src)
 {
-  assert(size == src.size);
+  size = src.size;
   memcpy(data, src.data, size);
 }
 
@@ -305,6 +433,76 @@ NdbBlob::getDistKey(Uint32 part)
   return (part / theStripeSize) % theStripeSize;
 }
 
+// pack/unpack table/index key  XXX support routines, shortcuts
+
+int
+NdbBlob::packKeyValue(const NdbTableImpl* aTable, const Buf& srcBuf)
+{
+  DBUG_ENTER("NdbBlob::packKeyValue");
+  const Uint32* data = (const Uint32*)srcBuf.data;
+  unsigned pos = 0;
+  Uint32* pack_data = (Uint32*)thePackKeyBuf.data;
+  unsigned pack_pos = 0;
+  for (unsigned i = 0; i < aTable->m_columns.size(); i++) {
+    NdbColumnImpl* c = aTable->m_columns[i];
+    assert(c != NULL);
+    if (c->m_pk) {
+      unsigned len = c->m_attrSize * c->m_arraySize;
+      Uint32 pack_len;
+      bool ok = c->get_var_length(&data[pos], pack_len);
+      if (! ok) {
+        setErrorCode(NdbBlobImpl::ErrCorruptPK);
+        DBUG_RETURN(-1);
+      }
+      memcpy(&pack_data[pack_pos], &data[pos], pack_len);
+      while (pack_len % 4 != 0) {
+        char* p = (char*)&pack_data[pack_pos] + pack_len++;
+        *p = 0;
+      }
+      pos += (len + 3) / 4;
+      pack_pos += pack_len / 4;
+    }
+  }
+  assert(4 * pos == srcBuf.size);
+  assert(4 * pack_pos <= thePackKeyBuf.maxsize);
+  thePackKeyBuf.size = 4 * pack_pos;
+  thePackKeyBuf.zerorest();
+  DBUG_RETURN(0);
+}
+
+int
+NdbBlob::unpackKeyValue(const NdbTableImpl* aTable, Buf& dstBuf)
+{
+  DBUG_ENTER("NdbBlob::unpackKeyValue");
+  Uint32* data = (Uint32*)dstBuf.data;
+  unsigned pos = 0;
+  const Uint32* pack_data = (const Uint32*)thePackKeyBuf.data;
+  unsigned pack_pos = 0;
+  for (unsigned i = 0; i < aTable->m_columns.size(); i++) {
+    NdbColumnImpl* c = aTable->m_columns[i];
+    assert(c != NULL);
+    if (c->m_pk) {
+      unsigned len = c->m_attrSize * c->m_arraySize;
+      Uint32 pack_len;
+      bool ok = c->get_var_length(&pack_data[pack_pos], pack_len);
+      if (! ok) {
+        setErrorCode(NdbBlobImpl::ErrCorruptPK);
+        DBUG_RETURN(-1);
+      }
+      memcpy(&data[pos], &pack_data[pack_pos], pack_len);
+      while (pack_len % 4 != 0) {
+        char* p = (char*)&data[pos] + pack_len++;
+        *p = 0;
+      }
+      pos += (len + 3) / 4;
+      pack_pos += pack_len / 4;
+    }
+  }
+  assert(4 * pos == dstBuf.size);
+  assert(4 * pack_pos == thePackKeyBuf.size);
+  DBUG_RETURN(0);
+}
+
 // getters and setters
 
 int
@@ -347,13 +545,15 @@ NdbBlob::setTableKeyValue(NdbOperation* 
     assert(c != NULL);
     if (c->m_pk) {
       unsigned len = c->m_attrSize * c->m_arraySize;
-      if (anOp->equal_impl(c, (const char*)&data[pos], len) == -1) {
+      if (anOp->equal_impl(c, (const char*)&data[pos]) == -1) {
         setErrorCode(anOp);
         DBUG_RETURN(-1);
       }
       pos += (len + 3) / 4;
     }
   }
+  if (theNdbOp->theDistrKeyIndicator_)
+    anOp->setPartitionId(theNdbOp->getPartitionId());
   assert(pos == theKeyBuf.size / 4);
   DBUG_RETURN(0);
 }
@@ -371,7 +571,7 @@ NdbBlob::setAccessKeyValue(NdbOperation*
     assert(c != NULL);
     if (c->m_pk) {
       unsigned len = c->m_attrSize * c->m_arraySize;
-      if (anOp->equal_impl(c, (const char*)&data[pos], len) == -1) {
+      if (anOp->equal_impl(c, (const char*)&data[pos]) == -1) {
         setErrorCode(anOp);
         DBUG_RETURN(-1);
       }
@@ -386,10 +586,10 @@ int
 NdbBlob::setPartKeyValue(NdbOperation* anOp, Uint32 part)
 {
   DBUG_ENTER("NdbBlob::setPartKeyValue");
-  DBUG_PRINT("info", ("dist=%u part=%u key=", getDistKey(part), part));
-  DBUG_DUMP("info", theKeyBuf.data, 4 * theTable->m_keyLenInWords);
+  DBUG_PRINT("info", ("dist=%u part=%u packkey=", getDistKey(part), part));
+  DBUG_DUMP("info", thePackKeyBuf.data, 4 * thePackKeyBuf.size);
   // TODO use attr ids after compatibility with 4.1.7 not needed
-  if (anOp->equal("PK", theKeyBuf.data) == -1 ||
+  if (anOp->equal("PK", thePackKeyBuf.data) == -1 ||
       anOp->equal("DIST", getDistKey(part)) == -1 ||
       anOp->equal("PART", part) == -1) {
     setErrorCode(anOp);
@@ -407,6 +607,12 @@ NdbBlob::getHeadInlineValue(NdbOperation
     setErrorCode(anOp);
     DBUG_RETURN(-1);
   }
+  /*
+   * If we get no data from this op then the operation is aborted
+   * one way or other.  Following hack in 5.0 makes sure we don't read
+   * garbage.  The proper fix exists only in version >= 5.1.
+   */
+  theHead->length = 0;
   DBUG_RETURN(0);
 }
 
@@ -416,8 +622,10 @@ NdbBlob::getHeadFromRecAttr()
   DBUG_ENTER("NdbBlob::getHeadFromRecAttr");
   assert(theHeadInlineRecAttr != NULL);
   theNullFlag = theHeadInlineRecAttr->isNULL();
-  assert(theNullFlag != -1);
+  assert(theEventBlobVersion >= 0 || theNullFlag != -1);
   theLength = ! theNullFlag ? theHead->length : 0;
+  DBUG_PRINT("info", ("theNullFlag=%d theLength=%llu",
+                      theNullFlag, theLength));
   DBUG_VOID_RETURN;
 }
 
@@ -430,7 +638,7 @@ NdbBlob::setHeadInlineValue(NdbOperation
     memset(theInlineData + theLength, 0, theInlineSize - theLength);
   assert(theNullFlag != -1);
   const char* aValue = theNullFlag ? 0 : theHeadInlineBuf.data;
-  if (anOp->setValue(theColumn, aValue, theHeadInlineBuf.size) == -1) {
+  if (anOp->setValue(theColumn, aValue) == -1) {
     setErrorCode(anOp);
     DBUG_RETURN(-1);
   }
@@ -521,7 +729,19 @@ NdbBlob::setActiveHook(ActiveHook active
 // misc operations
 
 int
-NdbBlob::getNull(bool& isNull)
+NdbBlob::getDefined(int& isNull) // deprecated
+{
+  DBUG_ENTER("NdbBlob::getDefined");
+  if (theState == Prepared && theSetFlag) {
+    isNull = (theSetBuf == NULL);
+    DBUG_RETURN(0);
+  }
+  isNull = theNullFlag;
+  DBUG_RETURN(0);
+}
+
+int
+NdbBlob::getNull(bool& isNull) // deprecated
 {
   DBUG_ENTER("NdbBlob::getNull");
   if (theState == Prepared && theSetFlag) {
@@ -537,6 +757,23 @@ NdbBlob::getNull(bool& isNull)
 }
 
 int
+NdbBlob::getNull(int& isNull)
+{
+  DBUG_ENTER("NdbBlob::getNull");
+  if (theState == Prepared && theSetFlag) {
+    isNull = (theSetBuf == NULL);
+    DBUG_RETURN(0);
+  }
+  isNull = theNullFlag;
+  if (isNull == -1 && theEventBlobVersion == -1) {
+    setErrorCode(NdbBlobImpl::ErrState);
+    DBUG_RETURN(-1);
+  }
+  DBUG_PRINT("info", ("isNull=%d", isNull));
+  DBUG_RETURN(0);
+}
+
+int
 NdbBlob::setNull()
 {
   DBUG_ENTER("NdbBlob::setNull");
@@ -882,6 +1119,18 @@ NdbBlob::readParts(char* buf, Uint32 par
 {
   DBUG_ENTER("NdbBlob::readParts");
   DBUG_PRINT("info", ("part=%u count=%u", part, count));
+  int ret;
+  if (theEventBlobVersion == -1)
+    ret = readTableParts(buf, part, count);
+  else
+    ret = readEventParts(buf, part, count);
+  DBUG_RETURN(ret);
+}
+
+int
+NdbBlob::readTableParts(char* buf, Uint32 part, Uint32 count)
+{
+  DBUG_ENTER("NdbBlob::readTableParts");
   Uint32 n = 0;
   while (n < count) {
     NdbOperation* tOp = theNdbCon->getNdbOperation(theBlobTable);
@@ -892,7 +1141,7 @@ NdbBlob::readParts(char* buf, Uint32 par
       setErrorCode(tOp);
       DBUG_RETURN(-1);
     }
-    tOp->m_abortOption = NdbTransaction::AbortOnError;
+    tOp->m_abortOption = NdbOperation::AbortOnError;
     buf += thePartSize;
     n++;
     thePendingBlobOps |= (1 << NdbOperation::ReadRequest);
@@ -902,6 +1151,18 @@ NdbBlob::readParts(char* buf, Uint32 par
 }
 
 int
+NdbBlob::readEventParts(char* buf, Uint32 part, Uint32 count)
+{
+  DBUG_ENTER("NdbBlob::readEventParts");
+  int ret = theEventOp->readBlobParts(buf, this, part, count);
+  if (ret != 0) {
+    setErrorCode(theEventOp);
+    DBUG_RETURN(-1);
+  }
+  DBUG_RETURN(0);
+}
+
+int
 NdbBlob::insertParts(const char* buf, Uint32 part, Uint32 count)
 {
   DBUG_ENTER("NdbBlob::insertParts");
@@ -916,7 +1177,7 @@ NdbBlob::insertParts(const char* buf, Ui
       setErrorCode(tOp);
       DBUG_RETURN(-1);
     }
-    tOp->m_abortOption = NdbTransaction::AbortOnError;
+    tOp->m_abortOption = NdbOperation::AbortOnError;
     buf += thePartSize;
     n++;
     thePendingBlobOps |= (1 << NdbOperation::InsertRequest);
@@ -940,7 +1201,7 @@ NdbBlob::updateParts(const char* buf, Ui
       setErrorCode(tOp);
       DBUG_RETURN(-1);
     }
-    tOp->m_abortOption = NdbTransaction::AbortOnError;
+    tOp->m_abortOption = NdbOperation::AbortOnError;
     buf += thePartSize;
     n++;
     thePendingBlobOps |= (1 << NdbOperation::UpdateRequest);
@@ -963,7 +1224,7 @@ NdbBlob::deleteParts(Uint32 part, Uint32
       setErrorCode(tOp);
       DBUG_RETURN(-1);
     }
-    tOp->m_abortOption = NdbTransaction::AbortOnError;
+    tOp->m_abortOption = NdbOperation::AbortOnError;
     n++;
     thePendingBlobOps |= (1 << NdbOperation::DeleteRequest);
     theNdbCon->thePendingBlobOps |= (1 << NdbOperation::DeleteRequest);
@@ -999,7 +1260,7 @@ NdbBlob::deletePartsUnknown(Uint32 part)
         setErrorCode(tOp);
         DBUG_RETURN(-1);
       }
-      tOp->m_abortOption= NdbTransaction::AO_IgnoreError;
+      tOp->m_abortOption= NdbOperation::AO_IgnoreError;
       n++;
     }
     DBUG_PRINT("info", ("bat=%u", bat));
@@ -1091,68 +1352,40 @@ NdbBlob::atPrepare(NdbTransaction* aCon,
   theTable = anOp->m_currentTable;
   theAccessTable = anOp->m_accessTable;
   theColumn = aColumn;
-  NdbDictionary::Column::Type partType = NdbDictionary::Column::Undefined;
-  switch (theColumn->getType()) {
-  case NdbDictionary::Column::Blob:
-    partType = NdbDictionary::Column::Binary;
-    theFillChar = 0x0;
-    break;
-  case NdbDictionary::Column::Text:
-    partType = NdbDictionary::Column::Char;
-    theFillChar = 0x20;
-    break;
-  default:
-    setErrorCode(NdbBlobImpl::ErrUsage);
+  // prepare blob column and table
+  if (prepareColumn() == -1)
     DBUG_RETURN(-1);
-  }
-  // sizes
-  theInlineSize = theColumn->getInlineSize();
-  thePartSize = theColumn->getPartSize();
-  theStripeSize = theColumn->getStripeSize();
-  // sanity check
-  assert((NDB_BLOB_HEAD_SIZE << 2) == sizeof(Head));
-  assert(theColumn->m_attrSize * theColumn->m_arraySize == sizeof(Head) +
theInlineSize);
-  if (thePartSize > 0) {
-    const NdbDictionary::Table* bt = NULL;
-    const NdbDictionary::Column* bc = NULL;
-    if (theStripeSize == 0 ||
-        (bt = theColumn->getBlobTable()) == NULL ||
-        (bc = bt->getColumn("DATA")) == NULL ||
-        bc->getType() != partType ||
-        bc->getLength() != (int)thePartSize) {
-      setErrorCode(NdbBlobImpl::ErrTable);
-      DBUG_RETURN(-1);
-    }
-    theBlobTable = &NdbTableImpl::getImpl(*bt);
-  }
-  // buffers
-  theKeyBuf.alloc(theTable->m_keyLenInWords << 2);
+  // extra buffers
   theAccessKeyBuf.alloc(theAccessTable->m_keyLenInWords << 2);
-  theHeadInlineBuf.alloc(sizeof(Head) + theInlineSize);
   theHeadInlineCopyBuf.alloc(sizeof(Head) + theInlineSize);
-  thePartBuf.alloc(thePartSize);
-  theHead = (Head*)theHeadInlineBuf.data;
-  theInlineData = theHeadInlineBuf.data + sizeof(Head);
   // handle different operation types
   bool supportedOp = false;
   if (isKeyOp()) {
     if (isTableOp()) {
       // get table key
-      Uint32* data = (Uint32*)theKeyBuf.data;
-      unsigned size = theTable->m_keyLenInWords;
+      Uint32* data = (Uint32*)thePackKeyBuf.data;
+      Uint32 size = theTable->m_keyLenInWords; // in-out
       if (theNdbOp->getKeyFromTCREQ(data, size) == -1) {
         setErrorCode(NdbBlobImpl::ErrUsage);
         DBUG_RETURN(-1);
       }
+      thePackKeyBuf.size = 4 * size;
+      thePackKeyBuf.zerorest();
+      if (unpackKeyValue(theTable, theKeyBuf) == -1)
+        DBUG_RETURN(-1);
     }
     if (isIndexOp()) {
       // get index key
-      Uint32* data = (Uint32*)theAccessKeyBuf.data;
-      unsigned size = theAccessTable->m_keyLenInWords;
+      Uint32* data = (Uint32*)thePackKeyBuf.data;
+      Uint32 size = theAccessTable->m_keyLenInWords; // in-out
       if (theNdbOp->getKeyFromTCREQ(data, size) == -1) {
         setErrorCode(NdbBlobImpl::ErrUsage);
         DBUG_RETURN(-1);
       }
+      thePackKeyBuf.size = 4 * size;
+      thePackKeyBuf.zerorest();
+      if (unpackKeyValue(theAccessTable, theAccessKeyBuf) == -1)
+        DBUG_RETURN(-1);
     }
     if (isReadOp()) {
       // upgrade lock mode
@@ -1192,6 +1425,105 @@ NdbBlob::atPrepare(NdbTransaction* aCon,
   DBUG_RETURN(0);
 }
 
+int
+NdbBlob::atPrepare(NdbEventOperationImpl* anOp, NdbEventOperationImpl* aBlobOp, const
NdbColumnImpl* aColumn, int version)
+{
+  DBUG_ENTER("NdbBlob::atPrepare [event]");
+  DBUG_PRINT("info", ("this=%p op=%p", this, anOp));
+  assert(theState == Idle);
+  assert(version == 0 || version == 1);
+  theEventBlobVersion = version;
+  // ndb api stuff
+  theNdb = anOp->m_ndb;
+  theEventOp = anOp;
+  theBlobEventOp = aBlobOp;
+  theTable = anOp->m_eventImpl->m_tableImpl;
+  theAccessTable = theTable;
+  theColumn = aColumn;
+  // prepare blob column and table
+  if (prepareColumn() == -1)
+    DBUG_RETURN(-1);
+  // tinyblob sanity
+  assert((theBlobEventOp == NULL) == (theBlobTable == NULL));
+  // extra buffers
+  theBlobEventDataBuf.alloc(thePartSize);
+  // prepare receive of head+inline
+  theHeadInlineRecAttr = theEventOp->getValue(aColumn, theHeadInlineBuf.data,
version);
+  if (theHeadInlineRecAttr == NULL) {
+    setErrorCode(theEventOp);
+    DBUG_RETURN(-1);
+  }
+  // prepare receive of blob part
+  if (theBlobEventOp != NULL) {
+    if ((theBlobEventPkRecAttr =
+           theBlobEventOp->getValue(theBlobTable->getColumn((Uint32)0),
+                                    thePackKeyBuf.data, version)) == NULL ||
+        (theBlobEventDistRecAttr =
+           theBlobEventOp->getValue(theBlobTable->getColumn((Uint32)1),
+                                    (char*)0, version)) == NULL ||
+        (theBlobEventPartRecAttr =
+           theBlobEventOp->getValue(theBlobTable->getColumn((Uint32)2),
+                                    (char*)&thePartNumber, version)) == NULL ||
+        (theBlobEventDataRecAttr =
+           theBlobEventOp->getValue(theBlobTable->getColumn((Uint32)3),
+                                    theBlobEventDataBuf.data, version)) == NULL) {
+      setErrorCode(theBlobEventOp);
+      DBUG_RETURN(-1);
+    }
+  }
+  setState(Prepared);
+  DBUG_RETURN(0);
+}
+
+int
+NdbBlob::prepareColumn()
+{
+  DBUG_ENTER("prepareColumn");
+  NdbDictionary::Column::Type partType = NdbDictionary::Column::Undefined;
+  switch (theColumn->getType()) {
+  case NdbDictionary::Column::Blob:
+    partType = NdbDictionary::Column::Binary;
+    theFillChar = 0x0;
+    break;
+  case NdbDictionary::Column::Text:
+    partType = NdbDictionary::Column::Char;
+    theFillChar = 0x20;
+    break;
+  default:
+    setErrorCode(NdbBlobImpl::ErrUsage);
+    DBUG_RETURN(-1);
+  }
+  // sizes
+  theInlineSize = theColumn->getInlineSize();
+  thePartSize = theColumn->getPartSize();
+  theStripeSize = theColumn->getStripeSize();
+  // sanity check
+  assert((NDB_BLOB_HEAD_SIZE << 2) == sizeof(Head));
+  assert(theColumn->m_attrSize * theColumn->m_arraySize == sizeof(Head) +
theInlineSize);
+  if (thePartSize > 0) {
+    const NdbTableImpl* bt = NULL;
+    const NdbColumnImpl* bc = NULL;
+    if (theStripeSize == 0 ||
+        (bt = theColumn->m_blobTable) == NULL ||
+        (bc = bt->getColumn("DATA")) == NULL ||
+        bc->getType() != partType ||
+        bc->getLength() != (int)thePartSize) {
+      setErrorCode(NdbBlobImpl::ErrTable);
+      DBUG_RETURN(-1);
+    }
+    // blob table
+    theBlobTable = &NdbTableImpl::getImpl(*bt);
+  }
+  // these buffers are always used
+  theKeyBuf.alloc(theTable->m_keyLenInWords << 2);
+  thePackKeyBuf.alloc(max(theTable->m_keyLenInWords,
theAccessTable->m_keyLenInWords) << 2);
+  theHeadInlineBuf.alloc(sizeof(Head) + theInlineSize);
+  theHead = (Head*)theHeadInlineBuf.data;
+  theInlineData = theHeadInlineBuf.data + sizeof(Head);
+  thePartBuf.alloc(thePartSize);
+  DBUG_RETURN(0);
+}
+
 /*
  * Before execute of prepared operation.  May add new operations before
  * this one.  May ask that this operation and all before it (a "batch")
@@ -1264,7 +1596,7 @@ NdbBlob::preExecute(NdbTransaction::Exec
         DBUG_RETURN(-1);
       }
       if (isWriteOp()) {
-        tOp->m_abortOption = NdbTransaction::AO_IgnoreError;
+        tOp->m_abortOption = NdbOperation::AO_IgnoreError;
       }
       theHeadInlineReadOp = tOp;
       // execute immediately
@@ -1283,7 +1615,7 @@ NdbBlob::preExecute(NdbTransaction::Exec
         if (tOp == NULL ||
             tOp->readTuple() == -1 ||
             setAccessKeyValue(tOp) == -1 ||
-            tOp->getValue(pkAttrId, theKeyBuf.data) == NULL) {
+            tOp->getValue(pkAttrId, thePackKeyBuf.data) == NULL) {
           setErrorCode(tOp);
           DBUG_RETURN(-1);
         }
@@ -1310,7 +1642,7 @@ NdbBlob::preExecute(NdbTransaction::Exec
         DBUG_RETURN(-1);
       }
       if (isWriteOp()) {
-        tOp->m_abortOption = NdbTransaction::AO_IgnoreError;
+        tOp->m_abortOption = NdbOperation::AO_IgnoreError;
       }
       theHeadInlineReadOp = tOp;
       // execute immediately
@@ -1372,10 +1704,13 @@ NdbBlob::postExecute(NdbTransaction::Exe
   assert(isKeyOp());
   if (isIndexOp()) {
     NdbBlob* tFirstBlob = theNdbOp->theBlobList;
-    if (this != tFirstBlob) {
+    if (this == tFirstBlob) {
+      packKeyValue(theTable, theKeyBuf);
+    } else {
       // copy key from first blob
-      assert(theKeyBuf.size == tFirstBlob->theKeyBuf.size);
-      memcpy(theKeyBuf.data, tFirstBlob->theKeyBuf.data,
tFirstBlob->theKeyBuf.size);
+      theKeyBuf.copyfrom(tFirstBlob->theKeyBuf);
+      thePackKeyBuf.copyfrom(tFirstBlob->thePackKeyBuf);
+      thePackKeyBuf.zerorest();
     }
   }
   if (isReadOp()) {
@@ -1480,7 +1815,7 @@ NdbBlob::postExecute(NdbTransaction::Exe
       setErrorCode(NdbBlobImpl::ErrAbort);
       DBUG_RETURN(-1);
     }
-    tOp->m_abortOption = NdbTransaction::AbortOnError;
+    tOp->m_abortOption = NdbOperation::AbortOnError;
     DBUG_PRINT("info", ("added op to update head+inline"));
   }
   DBUG_RETURN(0);
@@ -1510,7 +1845,7 @@ NdbBlob::preCommit()
           setErrorCode(NdbBlobImpl::ErrAbort);
           DBUG_RETURN(-1);
         }
-        tOp->m_abortOption = NdbTransaction::AbortOnError;
+        tOp->m_abortOption = NdbOperation::AbortOnError;
         DBUG_PRINT("info", ("added op to update head+inline"));
     }
   }
@@ -1529,12 +1864,17 @@ NdbBlob::atNextResult()
     DBUG_RETURN(-1);
   assert(isScanOp());
   // get primary key
-  { Uint32* data = (Uint32*)theKeyBuf.data;
-    unsigned size = theTable->m_keyLenInWords;
-    if (((NdbScanOperation*)theNdbOp)->getKeyFromKEYINFO20(data, size) == -1) {
+  { NdbScanOperation* tScanOp = (NdbScanOperation*)theNdbOp;
+    Uint32* data = (Uint32*)thePackKeyBuf.data;
+    unsigned size = theTable->m_keyLenInWords; // in-out
+    if (tScanOp->getKeyFromKEYINFO20(data, size) == -1) {
       setErrorCode(NdbBlobImpl::ErrUsage);
       DBUG_RETURN(-1);
     }
+    thePackKeyBuf.size = 4 * size;
+    thePackKeyBuf.zerorest();
+    if (unpackKeyValue(theTable, theKeyBuf) == -1)
+      DBUG_RETURN(-1);
   }
   getHeadFromRecAttr();
   if (setPos(0) == -1)
@@ -1554,6 +1894,30 @@ NdbBlob::atNextResult()
   DBUG_RETURN(0);
 }
 
+/*
+ * After next event on main table.
+ */
+int
+NdbBlob::atNextEvent()
+{
+  DBUG_ENTER("NdbBlob::atNextEvent");
+  Uint32 optype = 
+    SubTableData::getOperation(theEventOp->m_data_item->sdata->requestInfo);
+  DBUG_PRINT("info", ("this=%p op=%p blob op=%p version=%d optype=%u", this, theEventOp,
theBlobEventOp, theEventBlobVersion, optype));
+  if (theState == Invalid)
+    DBUG_RETURN(-1);
+  assert(theEventBlobVersion >= 0);
+  if (optype >= NdbDictionary::Event::_TE_FIRST_NON_DATA_EVENT)
+    DBUG_RETURN(0);
+  getHeadFromRecAttr();
+  if (theNullFlag == -1) // value not defined
+    DBUG_RETURN(0);
+  if (setPos(0) == -1)
+    DBUG_RETURN(-1);
+  setState(Active);
+  DBUG_RETURN(0);
+}
+
 // misc
 
 const NdbDictionary::Column*
@@ -1600,6 +1964,17 @@ NdbBlob::setErrorCode(NdbTransaction* aC
   if (theNdbCon != NULL && (code = theNdbCon->theError.code) != 0)
     ;
   else if ((code = theNdb->theError.code) != 0)
+    ;
+  else
+    code = NdbBlobImpl::ErrUnknown;
+  setErrorCode(code, invalidFlag);
+}
+
+void
+NdbBlob::setErrorCode(NdbEventOperationImpl* anOp, bool invalidFlag)
+{
+  int code = 0;
+  if ((code = anOp->m_error.code) != 0)
     ;
   else
     code = NdbBlobImpl::ErrUnknown;
Thread
bk commit into 5.1 tree (knielsen:1.2529)knielsen28 Mar