List:Commits« Previous MessageNext Message »
From:knielsen Date:January 12 2007 1:30pm
Subject:bk commit into 5.1 tree (knielsen:1.2387)
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-01-12 14:30:21+01:00, knielsen@ymer.(none) +28 -0
  Merge bk-internal:/home/bk/mysql-5.1-new-ndb
  into  ymer.(none):/usr/local/mysql/mysql-5.1-wl2223
  MERGE: 1.2343.1.3

  storage/ndb/include/kernel/signaldata/AttrInfo.hpp@stripped, 2007-01-12 14:30:13+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.4.1.1

  storage/ndb/include/kernel/signaldata/KeyInfo.hpp@stripped, 2007-01-12 14:30:13+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.5.1.1

  storage/ndb/include/kernel/signaldata/ScanFrag.hpp@stripped, 2007-01-12 14:30:13+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.13.1.1

  storage/ndb/include/kernel/signaldata/ScanTab.hpp@stripped, 2007-01-12 14:30:13+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.16.1.1

  storage/ndb/include/kernel/signaldata/TcKeyReq.hpp@stripped, 2007-01-12 14:30:13+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.8.1.1

  storage/ndb/include/ndbapi/Ndb.hpp@stripped, 2007-01-12 14:30:13+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.60.1.1

  storage/ndb/include/ndbapi/NdbDictionary.hpp@stripped, 2007-01-12 14:30:13+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.85.1.1

  storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp@stripped, 2007-01-12 14:30:13+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.26.1.1

  storage/ndb/include/ndbapi/NdbOperation.hpp@stripped, 2007-01-12 14:30:13+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.39.1.1

  storage/ndb/include/ndbapi/NdbReceiver.hpp@stripped, 2007-01-12 14:30:13+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.16.1.1

  storage/ndb/include/ndbapi/NdbScanOperation.hpp@stripped, 2007-01-12 14:30:13+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.43.1.1

  storage/ndb/include/ndbapi/NdbTransaction.hpp@stripped, 2007-01-12 14:30:13+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.52.1.1

  storage/ndb/ndbapi-examples/ndbapi_scan/ndbapi_scan.cpp@stripped, 2007-01-12 14:30:13+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.2.1.1

  storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp@stripped, 2007-01-12 14:30:13+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.128.2.1

  storage/ndb/src/ndbapi/Ndb.cpp@stripped, 2007-01-12 14:30:13+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.82.1.1

  storage/ndb/src/ndbapi/NdbDictionary.cpp@stripped, 2007-01-12 14:30:13+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.64.1.2

  storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp@stripped, 2007-01-12 14:30:14+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.154.1.1

  storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp@stripped, 2007-01-12 14:30:14+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.69.1.2

  storage/ndb/src/ndbapi/NdbIndexOperation.cpp@stripped, 2007-01-12 14:30:14+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.28.1.1

  storage/ndb/src/ndbapi/NdbOperation.cpp@stripped, 2007-01-12 14:30:14+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.19.1.1

  storage/ndb/src/ndbapi/NdbOperationExec.cpp@stripped, 2007-01-12 14:30:14+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.23.1.1

  storage/ndb/src/ndbapi/NdbReceiver.cpp@stripped, 2007-01-12 14:30:14+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.19.1.1

  storage/ndb/src/ndbapi/NdbScanOperation.cpp@stripped, 2007-01-12 14:30:14+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.103.1.1

  storage/ndb/src/ndbapi/NdbTransaction.cpp@stripped, 2007-01-12 14:30:14+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.66.1.8

  storage/ndb/src/ndbapi/NdbTransactionScan.cpp@stripped, 2007-01-12 14:30:14+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.17.1.1

  storage/ndb/src/ndbapi/ndberror.c@stripped, 2007-01-12 14:30:14+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.78.2.1

  storage/ndb/test/ndbapi/flexBench.cpp@stripped, 2007-01-12 14:30:14+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.13.1.1

  storage/ndb/tools/select_all.cpp@stripped, 2007-01-12 14:30:14+01:00, knielsen@ymer.(none) +0 -0
    Auto merged
    MERGE: 1.26.1.1

# 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-wl2223/RESYNC

--- 1.27/storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp	2007-01-12 14:30:30 +01:00
+++ 1.28/storage/ndb/include/ndbapi/NdbIndexScanOperation.hpp	2007-01-12 14:30:30 +01:00
@@ -143,11 +143,22 @@ public:
   /**
    * Marks end of a bound, 
    *  used when batching index reads (multiple ranges)
+   *
+   * With this call, it is possible to do multiple range scans (on the same
+   * table/index) in a single readTuples() operation and roundtrip. Each range
+   * bound (min and/or max) is defined with setBound(), and end_of_bound() is
+   * called when all setBound() calls for one range bound have been done.
+   *
+   * The RANGE_NO argument is an application-selected value (in the range
+   * 0-0xfff) that can be used to identify which range scan a particular row
+   * belong to; the value can be obtained from get_range_no() when rows are
+   * fetched with nextResult().
    */
   int end_of_bound(Uint32 range_no);
   
   /**
-   * Return range no for current row
+   * Return range no for current row, as defined in end_of_bound().
+   * Only available if the SF_ReadRangeNo is passed to readTuples().
    */
   int get_range_no();
   

--- 1.6/storage/ndb/include/kernel/signaldata/AttrInfo.hpp	2007-01-12 14:30:30 +01:00
+++ 1.7/storage/ndb/include/kernel/signaldata/AttrInfo.hpp	2007-01-12 14:30:30 +01:00
@@ -2,8 +2,7 @@
 
    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.
+   the Free Software Foundation; version 2 of the License.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of

--- 1.6/storage/ndb/include/kernel/signaldata/KeyInfo.hpp	2007-01-12 14:30:30 +01:00
+++ 1.7/storage/ndb/include/kernel/signaldata/KeyInfo.hpp	2007-01-12 14:30:30 +01:00
@@ -44,4 +44,27 @@ private:
   Uint32 keyData[DataLength];
 };
 
+/*
+  The KEYINFO signal is used to send a stream of data defining keys for
+  primary key operations (TCKEYREQ) or ordered index scan bounds (SCAN_TABREQ).
+
+  For TCKEYREQ, the first 8 words of the KEYINFO stream are actually stored
+  inside the TCKEYREQ signal, so for shorter keys, no KEYINFO signals are
+  needed. Otherwise as many consecutive KEYINFO signals as needed are sent with
+  max KeyInfo::Datalength words of data in each.
+
+  For scan bounds for ordered indexes, the data sent consists of a sequence of
+  entries, each (2+N) words:
+    1 word of bound type (0:<= 1:< 2:>= 3:> 4:==)
+    1 word of AttributeHeader (containing attribute Id and byte length)
+    N words of attribute data (N = (length+3)>>2).
+  Additionally, it is possible to send multiple range bounds in a single
+  SCAN_TABREQ and associated ATTRINFO stream (using
+  NdbIndexScanOperation::end_of_bound(RANGE_NO) ). In this case, the first word
+  of each range bound contains additional information: bits 16-31 holds the
+  length of this bound, in words of ATTRINFO data, and bits 4-11 holds a
+  number RANGE_NO specified by the application that can be read back from the
+  RANGE_NO pseudo-column.
+
+*/
 #endif

--- 1.14/storage/ndb/include/kernel/signaldata/ScanFrag.hpp	2007-01-12 14:30:30 +01:00
+++ 1.15/storage/ndb/include/kernel/signaldata/ScanFrag.hpp	2007-01-12 14:30:30 +01:00
@@ -75,6 +75,18 @@ public:
   static void setLcpScanFlag(Uint32 & requestInfo, Uint32 val);
 };
 
+/*
+  The KEYINFO20 signal is sent from LQH to API for each row in a scan when the
+  ScanTabReq::getKeyinfoFlag() is set in requestInfo in the SCAN_TABREQ signal.
+
+  The '20' in the signal name refers to the number of keyInfo data words in
+  the signal, which is actually a bit misleading since now it is sent as a
+  single long signal if the keyinfo has more than 20 words.
+
+  The information in this signal is used in the NDB API to request the take
+  over of a lock from the scan with a TCKEYREQ, using the primary key info
+  sent as data and the scanInfo_Node word to identify the lock.
+*/
 class KeyInfo20 {
   /**
    * Sender(s)
@@ -99,10 +111,23 @@ public:
 public:
   Uint32 clientOpPtr;
   Uint32 keyLen;
+  /*
+    The scanInfo_Node word contains the information needed to identify the
+    row and lock to take over in the TCKEYREQ signal. It has two parts:
+     1. ScanInfo      Lower 20 bits
+     2. ScanFragment  Upper 14 bits
+  */
   Uint32 scanInfo_Node;
   Uint32 transId1;
   Uint32 transId2;
   Uint32 keyData[DataLength];
+  /*
+    Note that if the key info data does not fit within the maximum of 20
+    in-signal words, the entire key info is instead sent in long signal
+    section 0.
+    The data here is a word string suitable for sending as KEYINFO in
+    the TCKEYREQ signal.
+  */
 };
 
 class ScanFragConf {

--- 1.17/storage/ndb/include/kernel/signaldata/ScanTab.hpp	2007-01-12 14:30:30 +01:00
+++ 1.18/storage/ndb/include/kernel/signaldata/ScanTab.hpp	2007-01-12 14:30:30 +01:00
@@ -57,6 +57,10 @@ private:
   UintR apiConnectPtr;        // DATA 0
   UintR attrLenKeyLen;        // DATA 1
   UintR requestInfo;          // DATA 2
+  /*
+    Table ID. Note that for a range scan of a table using an ordered index,
+    tableID is the ID of the index, not of the underlying table.
+  */
   UintR tableId;              // DATA 3
   UintR tableSchemaVersion;   // DATA 4
   UintR storedProcId;         // DATA 5
@@ -110,7 +114,11 @@ private:
  l = Lock mode             - 1  Bit 8
  h = Hold lock mode        - 1  Bit 10
  c = Read Committed        - 1  Bit 11
- k = Keyinfo               - 1  Bit 12
+ k = Keyinfo               - 1  Bit 12  If set, LQH will send back a KEYINFO20
+                                        signal for each scanned row,
+                                        containing information needed to
+                                        identify the row for subsequent
+                                        TCKEYREQ signal(s).
  t = Tup scan              - 1  Bit 13
  z = Descending (TUX)      - 1  Bit 14
  x = Range Scan (TUX)      - 1  Bit 15
@@ -346,7 +354,16 @@ private:
 
   struct OpData {
     Uint32 apiPtrI;
+    /*
+      tcPtrI is the scan fragment record pointer, used in SCAN_NEXTREQ to
+      acknowledge the reception of the batch of rows from a fragment scan.
+      If RNIL, this means that this particular fragment is done scanning.
+    */
     Uint32 tcPtrI;
+    /*
+      info encodes the number of rows and the length of the data sent in
+      TRANSID_AI signals.
+    */
     Uint32 info;
   };
 
@@ -414,10 +431,25 @@ private:
  
 };
 
-/**
- * 
- * SENDER:  API
- * RECIVER: Dbtc
+/*
+  SENDER:  API
+  RECIVER: Dbtc
+
+  This signal is sent by API to acknowledge the reception of batches of rows
+  from one or more fragment scans, and to request the fetching of the next
+  batches of rows.
+
+  Any locks held by the transaction on rows in the previously fetched batches
+  are released (unless explicitly transfered to this or another transaction in
+  a TCKEYREQ signal with TakeOverScanFlag set).
+
+  The fragment scan batches to acknowledge are identified by the tcPtrI words
+  in the list of struct OpData received in ScanTabConf (scan fragment record
+  pointer).
+
+  The list of scan fragment record pointers is sent as an array of words,
+  inline in the signal if <= 21 words, else as the first section in a long
+  signal.
  */
 class ScanNextReq {
   /**
@@ -454,7 +486,12 @@ private:
   UintR transId2;             // DATA 3
 
   // stopScan = 1, stop this scan
- 
+
+  /*
+    After this data comes the list of scan fragment record pointers for the
+    fragment scans to acknowledge, if they fit within the 25 words available
+    in the signal (else they are sent in the first long signal section).
+  */
 };
 
 #endif

--- 1.9/storage/ndb/include/kernel/signaldata/TcKeyReq.hpp	2007-01-12 14:30:30 +01:00
+++ 1.10/storage/ndb/include/kernel/signaldata/TcKeyReq.hpp	2007-01-12 14:30:30 +01:00
@@ -96,7 +96,7 @@ private:
   //  Conditional part = can be present in signal. 
   //  These four words will be sent only if their indicator is set.
   // ----------------------------------------------------------------------
-  UintR scanInfo;             // DATA 8   Various flags for scans
+  UintR scanInfo;             // DATA 8   Various flags for scans, see below
   UintR distrGroupHashValue;  // DATA 9
   UintR distributionKeySize;  // DATA 10
   UintR storedProcId;         // DATA 11
@@ -223,9 +223,18 @@ private:
 /**
  * Scan Info
  *
+ * Scan Info is used to identify the row and lock to take over from a scan.
+ *
+ * If "Scan take over indicator" is set, this operation will take over a lock
+ * currently held on a row being scanned.
+ * Scan locks not taken over in this way (by same or other transaction) are
+ * released when fetching the next batch of rows (SCAN_NEXTREQ signal).
+ * The value for "take over node" and "scan info" are obtained from the
+ * KEYINFO20 signal sent to NDB API by LQH if requested in SCAN_TABREQ.
+ *
  t = Scan take over indicator -  1 Bit
- n = Take over node           - 12 Bits -> max 65535
- p = Scan Info                - 18 Bits -> max 4095
+ n = Take over node           - 12 Bits -> max 4095
+ p = Scan Info                - 18 Bits -> max 0x3ffff
 
            1111111111222222222233
  01234567890123456789012345678901
@@ -238,7 +247,7 @@ private:
 #define TAKE_OVER_FRAG_MASK  (4095)
 
 #define SCAN_INFO_SHIFT      (1)
-#define SCAN_INFO_MASK       (262143)
+#define SCAN_INFO_MASK       (0x3ffff)
 
 /**
  * Attr Len

--- 1.62/storage/ndb/include/ndbapi/Ndb.hpp	2007-01-12 14:30:30 +01:00
+++ 1.63/storage/ndb/include/ndbapi/Ndb.hpp	2007-01-12 14:30:30 +01:00
@@ -2,8 +2,7 @@
 
    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.
+   the Free Software Foundation; version 2 of the License.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of

--- 1.55/storage/ndb/include/ndbapi/NdbTransaction.hpp	2007-01-12 14:30:30 +01:00
+++ 1.56/storage/ndb/include/ndbapi/NdbTransaction.hpp	2007-01-12 14:30:30 +01:00
@@ -2,8 +2,7 @@
 
    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.
+   the Free Software Foundation; version 2 of the License.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of

--- 1.88/storage/ndb/include/ndbapi/NdbDictionary.hpp	2007-01-12 14:30:30 +01:00
+++ 1.89/storage/ndb/include/ndbapi/NdbDictionary.hpp	2007-01-12 14:30:30 +01:00
@@ -2,8 +2,7 @@
 
    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.
+   the Free Software Foundation; version 2 of the License.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of

--- 1.41/storage/ndb/include/ndbapi/NdbOperation.hpp	2007-01-12 14:30:30 +01:00
+++ 1.42/storage/ndb/include/ndbapi/NdbOperation.hpp	2007-01-12 14:30:30 +01:00
@@ -2,8 +2,7 @@
 
    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.
+   the Free Software Foundation; version 2 of the License.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of

--- 1.18/storage/ndb/include/ndbapi/NdbReceiver.hpp	2007-01-12 14:30:30 +01:00
+++ 1.19/storage/ndb/include/ndbapi/NdbReceiver.hpp	2007-01-12 14:30:30 +01:00
@@ -2,8 +2,7 @@
 
    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.
+   the Free Software Foundation; version 2 of the License.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of

--- 1.44/storage/ndb/include/ndbapi/NdbScanOperation.hpp	2007-01-12 14:30:30 +01:00
+++ 1.45/storage/ndb/include/ndbapi/NdbScanOperation.hpp	2007-01-12 14:30:30 +01:00
@@ -41,12 +41,35 @@ public:
    * readTuples.
    */
   enum ScanFlag {
-    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
-    SF_KeyInfo = 1              // request KeyInfo to be sent back
+    /* Scan TUP order */
+    SF_TupScan = (1 << 16),
+    /* Scan in DISK order */
+    SF_DiskScan = (2 << 16),
+    /*
+      Return rows from an index scan sorted, ordered on the index key.
+      This flag makes the API perform a merge-sort among the ordered scans of
+      each fragment, to get a single sorted result set.
+    */
+    SF_OrderBy = (1 << 24),
+    /* Index scan in descending order, instead of default ascending. */
+    SF_Descending = (2 << 24),
+    /*
+      Enable @ref get_range_no (index scan only).
+      When this flag is set, NdbIndexScanOperation::get_range_no() can be
+      called to read back the range_no defined in
+      NdbIndexScanOperation::end_of_bound(). See @ref end_of_bound() for
+      explanation.
+    */
+    SF_ReadRangeNo = (4 << 24),
+    /*
+      Request KeyInfo to be sent back.
+      This enables the option to take over row lock taken by the scan using
+      lockCurrentTuple(), by making sure that the kernel sends back the
+      information needed to identify the row and the lock.
+      It is enabled by default for scans using LM_Exclusive, but must be
+      explicitly specified to enable the taking-over of LM_Read locks.
+    */
+    SF_KeyInfo = 1
   };
 
   /**
@@ -54,7 +77,8 @@ public:
    * 
    * @param lock_mode Lock mode
    * @param scan_flags see @ref ScanFlag
-   * @param parallel No of fragments to scan in parallel (0=max)
+   * @param parallel Number of fragments to scan in parallel (0=max)
+   * @param batch Number of rows to fetch in each batch
    */ 
   virtual
   int readTuples(LockMode lock_mode = LM_Read, 
@@ -100,25 +124,33 @@ public:
    * @param fetchAllowed  If set to false, then fetching is disabled
    * @param forceSend If true send will occur immediately (see @ref secAdapt)
    *
-   * The NDB API will contact the NDB Kernel for more tuples 
-   * when necessary to do so unless you set the fetchAllowed 
-   * to false. 
-   * This will force NDB to process any records it
-   * already has in it's caches. When there are no more cached 
-   * records it will return 2. You must then call nextResult
-   * with fetchAllowed = true in order to contact NDB for more 
-   * records.
+   * The NDB API will receive tuples from each fragment in batches, and
+   * needs to explicitly request from the NDB Kernel the sending of each new
+   * batch. When a new batch is requested, the NDB Kernel will remove any
+   * locks taken on rows in the previous batch, unless they have been already
+   * taken over by the application executing updateCurrentTuple(),
+   * lockCurrentTuple(), etc.
+   *
+   * The fetchAllowed parameter is used to control this release of
+   * locks from the application. When fetchAllowed is set to false,
+   * the NDB API will not request new batches from the NDB Kernel when
+   * all received rows have been exhausted, but will instead return 2
+   * from nextResult(), indicating that new batches must be
+   * requested. You must then call nextResult with fetchAllowed = true
+   * in order to contact the NDB Kernel for more records, after taking over
+   * locks as appropriate.
    *
    * fetchAllowed = false is useful when you want to update or 
    * delete all the records fetched in one transaction(This will save a
    *  lot of round trip time and make updates or deletes of scanned 
-   * records a lot faster). 
-   * While nextResult(false)
-   * returns 0 take over the record to another transaction. When 
-   * nextResult(false) returns 2 you must execute and commit the other 
-   * transaction. This will cause the locks to be transferred to the 
-   * other transaction, updates or deletes will be made and then the 
-   * locks will be released.
+   * records a lot faster).
+   *
+   * While nextResult(false) returns 0, take over the record to
+   * another transaction. When nextResult(false) returns 2 you must
+   * execute and commit the other transaction. This will cause the
+   * locks to be transferred to the other transaction, updates or
+   * deletes will be made and then the locks will be released.
+   *
    * After that, call nextResult(true) which will fetch new records and
    * cache them in the NdbApi. 
    * 
@@ -219,6 +251,12 @@ protected:
 
   // Scan related variables
   Uint32 theParallelism;
+  /*
+    Whether keyInfo is requested from Kernel.
+    KeyInfo is requested by application (using the SF_KeyInfo scan flag), and
+    also enabled automatically when using exclusive locking (lockmode
+    LM_Exclusive), or when requesting blobs (getBlobHandle()).
+  */
   Uint32 m_keyInfo;
 
   int getFirstATTRINFOScan();
@@ -233,22 +271,47 @@ protected:
 
   Uint32* m_prepared_receivers;   // These are to be sent
 
-  /**
-   * owned by API/user thread
+  /*
+    Owned by API/user thread.
+
+    These receivers, stored in the m_api_receivers array, have all attributes
+    from the current batch fully received, and the API thread has moved them
+    here (under mutex protection) from m_conf_receivers, so that all further
+    nextResult() can access them without extra mutex contention.
+
+    The m_current_api_receiver member is the index (into m_api_receivers) of
+    the receiver that delivered the last row to the application in
+    nextResult(). If no rows have been delivered yet, it is set to 0 for table
+    scans and to one past the end of the array for ordered index scans.
+
+    For ordered index scans, the m_api_receivers array is further kept sorted.
+    The entries from (m_current_api_receiver+1) to the end of the array are
+    kept in the order that their first row will be returned in nextResult().
+
+    Note also that for table scans, the entries available to the API thread
+    are stored in entries 0..(m_api_receivers_count-1), while for ordered
+    index scans, they are stored in entries m_current_api_receiver..array end.
    */
   Uint32 m_current_api_receiver;
   Uint32 m_api_receivers_count;
   NdbReceiver** m_api_receivers;  // These are currently used by api
   
-  /**
-   * owned by receiver thread
+  /*
+    Shared by receiver thread and API thread.
+    These are receivers that the receiver thread has obtained all attribute
+    data for (of the current batch).
+    API thread will move them (under mutex protection) to m_api_receivers on
+    first access with nextResult().
    */
   Uint32 m_conf_receivers_count;  // NOTE needs mutex to access
   NdbReceiver** m_conf_receivers; // receive thread puts them here
   
-  /**
-   * owned by receiver thread
-   */
+  /*
+   Owned by receiver thread
+   These are the receivers that the receiver thread is currently receiving
+   attribute data for (of the current batch).
+   Once all is received, they will be moved to m_conf_receivers.
+  */
   Uint32 m_sent_receivers_count;  // NOTE needs mutex to access
   NdbReceiver** m_sent_receivers; // receive thread puts them here
   
@@ -263,7 +326,16 @@ protected:
   bool m_ordered;
   bool m_descending;
   Uint32 m_read_range_no;
-  NdbRecAttr *m_curr_row; // Pointer to last returned row
+  /*
+    m_curr_row: Pointer to last returned row (linked list of NdbRecAttr
+    objects).
+    First comes keyInfo, if requested (explicitly with SF_KeyInfo, or
+    implicitly when using LM_Exclusive).
+    Then comes range_no, if requested with SF_ReadRangeNo, included first in
+    the list of sort columns to get sorting of multiple range scans right.
+    Then the 'real' columns that are participating in the scan.    
+  */
+  NdbRecAttr *m_curr_row;
   bool m_executed; // Marker if operation should be released at close
 };
 

--- 1.131/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp	2007-01-12 14:30:30 +01:00
+++ 1.132/storage/ndb/src/kernel/blocks/dbtc/DbtcMain.cpp	2007-01-12 14:30:30 +01:00
@@ -8526,16 +8526,14 @@ void Dbtc::systemErrorLab(Signal* signal
   when it has retrived at least one tuple and is hindered by a lock to
   retrieve the next tuple.  This is to ensure that a scan process never 
   can be involved in a deadlock situation.   
-   
-  When the scan process receives a number of tuples to report to the 
-  application it checks the state of the delivery process. Only one delivery 
-  at a time is handled by the application. Thus if the delivery process 
-  has already sent a number of tuples to the application this set of tuples 
-  are queued.
-   
-  When the application requests the next set of tuples it is immediately
-  delivered if any are queued, otherwise it waits for the next scan
-  process that is ready to deliver.  
+
+  Tuples from each fragment scan are sent directly to API from TUP, and tuples
+  from different fragments are delivered in parallel (so will be interleaved
+  when received).
+
+  When a batch of tuples from one fragment has been fully fetched, the scan of
+  that fragment will not continue until the previous batch has been
+  acknowledged by API with a SCAN_NEXTREQ signal.
 
 
   ERROR HANDLING
@@ -9460,7 +9458,7 @@ void Dbtc::execSCAN_FRAGCONF(Signal* sig
 /****************************************************************************
  * execSCAN_NEXTREQ
  *
- * THE APPLICATION HAVE PROCESSED THE TUPLES TRANSFERRED AND IS NOW READY FOR
+ * THE APPLICATION HAS PROCESSED THE TUPLES TRANSFERRED AND IS NOW READY FOR
  * MORE. THIS SIGNAL IS ALSO USED TO CLOSE THE SCAN. 
  ****************************************************************************/
 void Dbtc::execSCAN_NEXTREQ(Signal* signal) 

--- 1.83/storage/ndb/src/ndbapi/Ndb.cpp	2007-01-12 14:30:30 +01:00
+++ 1.84/storage/ndb/src/ndbapi/Ndb.cpp	2007-01-12 14:30:30 +01:00
@@ -316,14 +316,20 @@ Ndb::startTransaction(const NdbDictionar
       Uint32 hashValue;
       {
 	Uint32 buf[4];
+        Uint64 tmp[1000];
+
+        if (keyLen >= sizeof(tmp))
+        {
+          theError.code = 4207;
+          DBUG_RETURN(NULL);
+        }
 	if((UintPtr(keyData) & 7) == 0 && (keyLen & 3) == 0)
 	{
 	  md5_hash(buf, (const Uint64*)keyData, keyLen >> 2);
 	}
 	else
 	{
-	  Uint64 tmp[1000];
-	  tmp[keyLen/8] = 0;
+          tmp[keyLen/8] = 0;    // Zero out any 64-bit padding
 	  memcpy(tmp, keyData, keyLen);
 	  md5_hash(buf, tmp, (keyLen+3) >> 2);	  
 	}

--- 1.71/storage/ndb/src/ndbapi/NdbTransaction.cpp	2007-01-12 14:30:30 +01:00
+++ 1.72/storage/ndb/src/ndbapi/NdbTransaction.cpp	2007-01-12 14:30:30 +01:00
@@ -2,8 +2,7 @@
 
    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.
+   the Free Software Foundation; version 2 of the License.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -478,6 +477,7 @@ NdbTransaction::executeNoBlobs(ExecType 
          * This timeout situation can occur if NDB crashes.
          */
         ndbout << "This timeout should never occur, execute(..)" << endl;
+	theError.code = 4012;
         setOperationErrorCodeAbort(4012);  // Error code for "Cluster Failure"
         DBUG_RETURN(-1);
       }//if
@@ -2211,6 +2211,14 @@ NdbTransaction::receiveTCINDXCONF(const 
       }
     } else if ((tNoComp >= tNoSent) &&
                (theLastExecOpInList->theCommitIndicator == 1)){
+
+      if (m_abortOption == AO_IgnoreError && theError.code != 0){
+	/**
+	 * There's always a TCKEYCONF when using IgnoreError
+	 */
+	return -1;
+      }
+
       /**********************************************************************/
       // We sent the transaction with Commit flag set and received a CONF with
       // no Commit flag set. This is clearly an anomaly.

--- 1.18/storage/ndb/src/ndbapi/NdbTransactionScan.cpp	2007-01-12 14:30:30 +01:00
+++ 1.19/storage/ndb/src/ndbapi/NdbTransactionScan.cpp	2007-01-12 14:30:30 +01:00
@@ -86,6 +86,9 @@ NdbTransaction::receiveSCAN_TABCONF(NdbA
   const ScanTabConf * conf = CAST_CONSTPTR(ScanTabConf, aSignal->getDataPtr());
   if(checkState_TransId(&conf->transId1)){
     
+    /*
+      If both EndOfData is set and number of operations is 0, close the scan.
+    */
     if (conf->requestInfo == ScanTabConf::EndOfData) {
       theScanningOp->execCLOSE_SCAN_REP();
       return 0;

--- 1.68/storage/ndb/src/ndbapi/NdbDictionary.cpp	2007-01-12 14:30:30 +01:00
+++ 1.69/storage/ndb/src/ndbapi/NdbDictionary.cpp	2007-01-12 14:30:30 +01:00
@@ -2,8 +2,7 @@
 
    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.
+   the Free Software Foundation; version 2 of the License.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of

--- 1.157/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp	2007-01-12 14:30:30 +01:00
+++ 1.158/storage/ndb/src/ndbapi/NdbDictionaryImpl.cpp	2007-01-12 14:30:30 +01:00
@@ -4516,6 +4516,165 @@ NdbDictionaryImpl::dropLogfileGroup(cons
   return m_receiver.drop_filegroup(fg);
 }
 
+static int
+cmp_ndbrec_attr(const void *a, const void *b)
+{
+  const NdbRecord::Attr *r1= (const NdbRecord::Attr *)a;
+  const NdbRecord::Attr *r2= (const NdbRecord::Attr *)b;
+  if(r1->attrId < r2->attrId)
+    return -1;
+  else if(r1->attrId == r2->attrId)
+    return 0;
+  else
+    return 1;
+}
+
+NdbRecord *
+NdbDictionaryImpl::createRecord(const NdbTableImpl *table,
+                                const NdbDictionary::RecordSpecification *recSpec,
+                                Uint32 length,
+                                Uint32 elemSize)
+{
+  NdbRecord *rec= NULL;
+  Uint32 tableNumPK;
+  Uint32 oldAttrId;
+  Uint32 numPK;
+
+  /*
+    In later versions we can use elemSize to provide backwards
+    compatibility if we extend the RecordSpecification structure.
+  */
+  if (elemSize != sizeof(NdbDictionary::RecordSpecification))
+  {
+    m_error.code= 4276;
+    return NULL;
+  }
+
+  rec= (NdbRecord *)
+    calloc(1, sizeof(NdbRecord) + (length-1)*elemSize);
+  if (!rec)
+  {
+    m_error.code= 4000;
+    return NULL;
+  }
+
+  rec->tableId= table->m_id;
+  rec->tableVersion= table->m_version;
+  rec->flags= 0;
+  rec->totalTableColumns= table->m_columns.size();
+  rec->noOfColumns= length;
+
+  for (Uint32 i= 0; i<length; i++)
+  {
+    const NdbDictionary::RecordSpecification *rs= &recSpec[i];
+    const NdbColumnImpl *col;
+    if (rs->colPtr)
+      col= &NdbColumnImpl::getImpl(*(rs->colPtr));
+    else if (rs->colName)
+      col= table->getColumn(rs->colName);
+    else
+      col= table->getColumn(rs->colNumber);
+    if(!col)
+    {
+      m_error.code= 4277;
+      goto err;
+    }
+
+    NdbRecord::Attr *recCol= &rec->columns[i];
+
+    bool isVarCol= (col->m_arrayType==NDB_ARRAYTYPE_SHORT_VAR ||
+                    col->m_arrayType==NDB_ARRAYTYPE_MEDIUM_VAR);
+
+    recCol->attrId= col->m_attrId;
+    recCol->offset= rs->dataOffset;
+    recCol->maxSize= col->m_attrSize*col->m_arraySize;
+    recCol->flags= 0;
+    if(col->m_pk)
+      recCol->flags|= NdbRecord::IsPK;
+
+    switch(rs->type)
+    {
+      case NdbDictionary::RecordSpecification::AttrOffsetNotNULL:
+        if (!isVarCol)
+        {
+          recCol->type= NdbRecord::AttrNotNULL;
+        }
+        else
+          assert(0);            // ToDo
+        break;
+
+      case NdbDictionary::RecordSpecification::AttrOffsetNULL:
+        assert(0);              // ToDo
+        break;
+
+      default:
+        /* Wrong type supplied by caller. */
+        m_error.code= 4118;
+        goto err;
+    }
+  }
+
+  /* Now we sort the array in attrId order. */
+  qsort(rec->columns,
+        rec->noOfColumns,
+        sizeof(rec->columns[0]),
+        cmp_ndbrec_attr);
+
+  /*
+    Now check for the presense of primary keys, and set flags for whether
+    this NdbRecord can be used for insert and/or for specifying keys for
+    read/update.
+
+    Also test for duplicate columns, easy now that they are sorted.
+  */
+
+  oldAttrId= ~0;
+  numPK= 0;
+  for (Uint32 i= 0; i<rec->noOfColumns; i++)
+  {
+    NdbRecord::Attr *recCol= &rec->columns[i];
+    if (i > 0 && oldAttrId==recCol->attrId)
+    {
+      m_error.code= 4278;
+      goto err;
+    }
+    oldAttrId= recCol->attrId;
+
+    if (recCol->flags & NdbRecord::IsPK)
+      numPK++;
+  }
+
+  /*
+    Since we checked for duplicates, we can check for primary key completeness
+    simply by counting.
+  */
+  tableNumPK= 0;
+  for (Uint32 i= 0; i<table->m_columns.size(); i++)
+  {
+    if (table->m_columns[i]->m_pk)
+      tableNumPK++;
+  }
+  if (numPK >= tableNumPK)
+  {
+    rec->flags|= NdbRecord::RecHasAllPKs;
+    if (numPK == tableNumPK)
+      rec->flags|= NdbRecord::RecIsPKRecord;
+  }
+
+  return rec;
+
+ err:
+  if (rec)
+    free(rec);
+  return NULL;
+}
+
+void NdbDictionaryImpl::releaseRecord_impl(NdbRecord *rec)
+{
+  if (rec)
+    free(rec);
+}
+
 int
 NdbDictInterface::create_file(const NdbFileImpl & file,
 			      const NdbFilegroupImpl & group,

--- 1.73/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp	2007-01-12 14:30:30 +01:00
+++ 1.74/storage/ndb/src/ndbapi/NdbDictionaryImpl.hpp	2007-01-12 14:30:30 +01:00
@@ -2,8 +2,7 @@
 
    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.
+   the Free Software Foundation; version 2 of the License.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -654,7 +653,7 @@ public:
   bool setTransporter(class TransporterFacade * tf);
 
   int createTable(NdbTableImpl &t);
-  int createBlobTables(NdbTableImpl& t);
+  int createBlobTables(NdbTableImpl& org, NdbTableImpl& created);
   int alterTable(NdbTableImpl &t);
   int dropTable(const char * name);
   int dropTable(NdbTableImpl &);

--- 1.29/storage/ndb/src/ndbapi/NdbIndexOperation.cpp	2007-01-12 14:30:30 +01:00
+++ 1.30/storage/ndb/src/ndbapi/NdbIndexOperation.cpp	2007-01-12 14:30:30 +01:00
@@ -2,8 +2,7 @@
 
    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.
+   the Free Software Foundation; version 2 of the License.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of

--- 1.20/storage/ndb/src/ndbapi/NdbOperation.cpp	2007-01-12 14:30:30 +01:00
+++ 1.21/storage/ndb/src/ndbapi/NdbOperation.cpp	2007-01-12 14:30:30 +01:00
@@ -2,8 +2,7 @@
 
    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.
+   the Free Software Foundation; version 2 of the License.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of

--- 1.25/storage/ndb/src/ndbapi/NdbOperationExec.cpp	2007-01-12 14:30:30 +01:00
+++ 1.26/storage/ndb/src/ndbapi/NdbOperationExec.cpp	2007-01-12 14:30:30 +01:00
@@ -2,8 +2,7 @@
 
    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.
+   the Free Software Foundation; version 2 of the License.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of

--- 1.21/storage/ndb/src/ndbapi/NdbReceiver.cpp	2007-01-12 14:30:30 +01:00
+++ 1.22/storage/ndb/src/ndbapi/NdbReceiver.cpp	2007-01-12 14:30:30 +01:00
@@ -2,8 +2,7 @@
 
    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.
+   the Free Software Foundation; version 2 of the License.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of

--- 1.105/storage/ndb/src/ndbapi/NdbScanOperation.cpp	2007-01-12 14:30:30 +01:00
+++ 1.106/storage/ndb/src/ndbapi/NdbScanOperation.cpp	2007-01-12 14:30:30 +01:00
@@ -2,8 +2,7 @@
 
    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.
+   the Free Software Foundation; version 2 of the License.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of

--- 1.16/storage/ndb/test/ndbapi/flexBench.cpp	2007-01-12 14:30:30 +01:00
+++ 1.17/storage/ndb/test/ndbapi/flexBench.cpp	2007-01-12 14:30:30 +01:00
@@ -2,8 +2,7 @@
 
    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.
+   the Free Software Foundation; version 2 of the License.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of

--- 1.27/storage/ndb/tools/select_all.cpp	2007-01-12 14:30:30 +01:00
+++ 1.28/storage/ndb/tools/select_all.cpp	2007-01-12 14:30:30 +01:00
@@ -364,20 +364,41 @@ int scanReadRecords(Ndb* pNdb, 
       return -1;
     }
 
-    if (rowid)
-      ndbout << "ROWID\t";
-    
-    if (gci)
-      ndbout << "\tGCI";
-    
-    if (headers && !nodata)
-      row->header(ndbout);
-    
-    if (disk_ref)
-      ndbout << "\tDISK_REF";
+    bool do_delimiter= false;
+    char delimiter_string[2];
+    delimiter_string[0]= delimiter;
+    delimiter_string[1]= '\0';
+#define DELIMITER if (do_delimiter) ndbout << delimiter_string; else do_delimiter= true
+    if (headers)
+    {
+      if (rowid)
+      {
+        DELIMITER;
+        ndbout << "ROWID";
+      }
+
+      if (gci)
+      {
+        DELIMITER;
+        ndbout << "GCI";
+      }
+
+      if (!nodata)
+      {
+        DELIMITER;
+        row->header(ndbout);
+      }
+
+      if (disk_ref)
+      {
+        DELIMITER;
+        ndbout << "DISK_REF";
+      }
+
+      ndbout << endl;
+    }
+#undef DELIMITER
 
-    ndbout << endl;
-    
     int eof;
     int rows = 0;
     eof = pOp->nextResult();

--- 1.81/storage/ndb/src/ndbapi/ndberror.c	2007-01-12 14:30:30 +01:00
+++ 1.82/storage/ndb/src/ndbapi/ndberror.c	2007-01-12 14:30:30 +01:00
@@ -615,6 +615,10 @@ ErrorBundle ErrorCodes[] = {
   { 4273, DMEC, IE, "No blob table in dict cache" },
   { 4274, DMEC, IE, "Corrupted main table PK in blob operation" },
   { 4275, DMEC, AE, "The blob method is incompatible with operation type or lock mode" },
+  { 4276, DMEC, AE, "API version mismatch or wrong sizeof(NdbDictionary::RecordSpecification)" },
+  { 4277, DMEC, AE, "Missing column specification in NdbDictionary::RecordSpecification" },
+  { 4278, DMEC, AE, "Duplicate column specification in NdbDictionary::RecordSpecification" },
+  { 4279, DMEC, AE, "NdbRecord for tuple access is not a primary key NdbRecord" },
 };
 
 static

--- 1.3/storage/ndb/ndbapi-examples/ndbapi_scan/ndbapi_scan.cpp	2007-01-12 14:30:30 +01:00
+++ 1.4/storage/ndb/ndbapi-examples/ndbapi_scan/ndbapi_scan.cpp	2007-01-12 14:30:30 +01:00
@@ -86,7 +86,7 @@ milliSleep(int milliseconds){
 
 
 /**
- * Helper sleep function
+ * Helper debugging macros
  */
 #define PRINT_ERROR(code,msg) \
   std::cout << "Error in " << __FILE__ << ", line: " << __LINE__ \
Thread
bk commit into 5.1 tree (knielsen:1.2387)knielsen12 Jan